由上節說明可以知道中,透過 LINQ 可以很快速地查詢 DataSet中的靜態資料。 但是這樣子並沒有顯現出 LINQ 最大的功能,那就是:設計階段強型別檢查 (strong type-checking at design time)。
要使用 LINQ to SQL 時,必須先建立連結到資料庫元素的 O/R map 。 這個 map 一旦建立,存取資料庫的語法就好像在寫物件式的程式碼,就變的既簡單又快速。
使用 LINQ to SQL 的幾個必須步驟:
- Add System.Data.Linq namespace which contains the DataContext object, which is the core object that connects the database
- Create an O/R map that connects objects to data tables, columns, and more.
- Connect to your database using the DataContext object of LINQ to SQL.
- Use the features of LINQ and LINQ to SQL to work with your database.
This includes writing queries using strongly typed objects. In addition, you can use the features of LINQ to SQL to insert, update, and delete data.
Mapping Objects to Relational Data
要使用物件來表達資料庫,首要工作就是建立相對應的物件。 底下三種方法都是用來建立 O/R map 物件的方法
Mapping with the Visual Studio Designer Tool
建立 O/R map 最簡單的方法就是透過 Visual Studio 的設計工具,它可以將資料庫物件直接拖拉到設計工具上,然後自動的幫我們建立資料庫物件類別。
The LINQ to SQL Classes file is of type *.dbml. The file contains XML that defines the metadata of your database. Behind this XML file, you will find a layout file for use by the designer (.layout), and a code file (.vb or .cs). The code file contains the actual objects against which you write your database code.
新增 LINQ to SQL 類別檔
建立的 DataContext 內容
底下類別是工具自動建立的物件內容
精簡後的 DataContext 類別 (*.dbml)
using System.Data.Linq.Mapping;
namespace Northwind_DBML
{
public partial class NorthwindDataContext : DataContext
{
private static MappingSource mappingSource = new AttributeMappingSource();
#region 擴充性方法定義
partial void OnCreated();
partial void InsertOrders(Orders instance);
partial void UpdateOrders(Orders instance);
partial void DeleteOrders(Orders instance);
partial void InsertOrder_Details(Order_Details instance);
partial void UpdateOrder_Details(Order_Details instance);
partial void DeleteOrder_Details(Order_Details instance);
partial void InsertProducts(Products instance);
partial void UpdateProducts(Products instance);
partial void DeleteProducts(Products instance);
#endregion
public System.Data.Linq.TableOrders{get;}
public System.Data.Linq.TableOrder_Details{get;}
public System.Data.Linq.TableProducts{get;}
}
public partial class Orders
{ }
public partial class Order_Details
{ }
public partial class Products
{ }
}
Mapping with the Command-Line Tool
透過命令列工具 SqlMetal.exe ,也可以產生 .dbml 檔和 O/R code。 這個方法最適合針對一整個大型資料庫做 mapping 時使用。例如:
To generate a .dbml file
sqlmetal "C:\Code\Northwind and Pubs Dbs\pubs.mdf" /language:vb /dbml:Pubs.dbml
To create the code
sqlmetal "C:\Code\Northwind and Pubs Dbs\pubs.mdf" /language:vb /code:Pubs.vb
Mapping Objcts to the Entity in the Code Editor
這方法就是自行撰寫 O/R map 程式碼,方法大至依照以下步驟:
1. 建立對應到資料庫的 Table 的類別檔,並引用以下命名空間
using System.Data.Linq;
using System.Data.Linq.Mapping;
[Table]
public class MyEmployees
{
...
}
2. 使用 Table屬性來描述自訂的類別,以對應到實體資料庫的 Table。
3. 使用 Column屬性描述該類別的 Property ,以對應到實體 Table 的 Column。
namespace C17_LINQ
{
[Table(Name = "Employees")]
public class Employees
{
private int _empID;
[Column(IsPrimaryKey = true, Name = "EmployeeId", Storage = "_empID")]
public int EmployeeId
{
get
{
return this._empID;
}
set
{
this._empID = value;
}
}
[Column(Name = "FirstName")]
public string FirstName { get; set; }
[Column(Name = "LastName")]
public string LastName { get; set; }
[Column(Name = "Age")]
public int Age { get; set; }
[Column(Name = "City")]
public string City { get; set; }
}
}
4. 建立一個可以用來公開這些 Table 類別的 Context 類別。
這個類別必須繼承 DataContext物件,DataContext物件可以幫我們透過資料庫連接對應到所有實體的來源。
namespace C17_LINQ
{
public class NorthwindCustomMap : DataContext
{
public Tableemployees;
// This constructor will call DataContext.DataContext()
public NorthwindCustomMap(string connection) : base(connection)
{
}
}
}
Query Data with LINQ to SQL
要使用 LINQ to SQL查詢資料就和使用 LINQ Query 的方法是一樣的。 最大的不同在於 LINQ to SQL可以透過 O/R Map 物件連接到真正的資料庫。
使用自訂的 DataContext 物件,操作 LINQ to SQL 查詢
使用自訂的 DataContext物件必須提供一個連線字串,以便連接資料庫。
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
//TableEmployees = db.GetTable ();
TableEmployees = db.employees;
IEnumerablequery =
from emp in Employees
where emp.FirstName.Length > 5
select emp;
gv1.DataSource = query;
gv1.DataBind();
使用自動產生的 DataContext 物件,操作 LINQ to SQL 查詢
使用自動產生的 DBML 檔,它會自動設定連線字串,並且建立繼承自 DataContext的物件。 我們只須建立它的 instance 就可以直接使用查詢。
NorthwindDataContext db = new NorthwindDataContext();
var query = from emp in db.Employees
where emp.FirstName.Length > 5
select emp;
gv1.DataSource = query;
gv1.DataBind();
Inserting, Updating, and Deleting with LINQ to SQL
LINQ to SQL makes inserting, updating, and deleting data in your database a very simple process. It creates the connections between your O/R map and your database. You simply need to make a modification to object instances and then save the changes. You work with your object model to add a new instance to a collection, modify a given object, or remove an object from the collection. Once complete, you call the SubmitChanges method of the DataContext object to write the results back to the database.
For example, if you wish to add a new order to the database, you start by creating a new order object. You then add it to the Orders table using the method InsertOnSubmit . When you are ready to submit all changes, you call SubmitChanges . The following code shows this example:
底下是 ITable型別公開的新增或刪除的方法:
- InsertOnSubmit:在這個資料表中加入一個 pending insert狀態的實體。
- DeleteOnSubmit:將此資料表中的指定實體,置於 pending delete狀態。
- InsertAllOnSubmit:將集合的所有實體加入至 pending insert 狀態中的 DataContext。
- DeleteAllOnSubmit:將集合中的所有實體置於 pending delete 狀態。
當變更資料結束時,必須叫用 DataContext的 SubmitChanges方法,以便將結果寫回資料庫。
底下範例示範如何使用 LINQ to SQL執行 CRUD 。
查詢
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
var query = from order in db.orders
where order.OrderID == 10248
orderby order.OrderID
select order;
gv1.DataSource = query.ToArray();
gv1.DataBind();
新增
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
Orders newOrder = new Orders();
newOrder.CustomerID = "VINET";
newOrder.EmployeeID = 5;
newOrder.OrderDate = DateTime.Now;
db.orders.InsertOnSubmit(newOrder);
db.SubmitChanges();
修改
若要修改資料,必須透過查詢先取得資料,更新後,再呼叫 SubmitChanges回存到資料庫。
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
//建立查詢語法
var query = from order in db.orders
where order.OrderID == 11081
select order;
//執行查詢語法
Orders updateOrder = query.First();
//以上,可以用另一種較簡單寫法,如下:
//var updateOrder = db.orders.First(o => o.OrderID == 11081);
//變更資料
updateOrder.OrderDate = DateTime.Now;
//更新資料庫資料
db.SubmitChanges();
刪除
若要刪除資料,只須將要刪除資料的執行個體傳給 DeleteOnSubmit方法即可。
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
var deleteOrder = db.orders.First(o => o.OrderID == 11081);
db.orders.DeleteOnSubmit(deleteOrder);
db.SubmitChanges();
Join with LINQ to SQL
Inner Join
使用 where 條件關連欄位
protected void btnJoin_LinqToSql_Click(object sender, EventArgs e)
{
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
var query = from O in db.orders
from OD in db.order_details
where O.OrderID == OD.OrderID && O.OrderID == 10248
select new { O.OrderID, OD.ProductID, OD.UnitPrice, OD.Quantity };
gv1.DataSource = query.ToArray();
gv1.DataBind();
myDebug.WriteLine(query.ToString());
//SELECT [t0].[OrderID], [t1].[ProductID], [t1].[UnitPrice], [t1].[Quantity]
//FROM [dbo].[Orders] AS [t0], [dbo].[Order Details] AS [t1]
//WHERE ([t0].[OrderID] = [t1].[OrderID]) AND ([t0].[OrderID] = @p0)
}
直接利用資料表的關連性
protected void btnJoin_LinqToSql_Relaction_Click(object sender, EventArgs e)
{
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
var query = from O in db.orders
from OD in O.Order_Details
where O.OrderID == 10248
select new
{ O.OrderID, OD.ProductID, OD.UnitPrice, OD.Quantity };
gv1.DataSource = query.ToArray();
gv1.DataBind();
myDebug.WriteLine(query.ToString());
//SELECT [t0].[OrderID], [t1].[ProductID], [t1].[UnitPrice], [t1].[Quantity]
//FROM [dbo].[Orders] AS [t0], [dbo].[Order Details] AS [t1]
//WHERE ([t0].[OrderID] = @p0) AND ([t1].[OrderID] = [t0].[OrderID])
}
Left Join
protected void btnLeftJoin_LinqToSql_Click(object sender, EventArgs e)
{
ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
NorthwindContext db = new NorthwindContext(connString.ConnectionString);
var query = from O in db.orders
join OD in db.order_details on O.OrderID equals OD.OrderID into ODS
from OD in ODS.DefaultIfEmpty()
where O.OrderID == 10248
select new
{ O.OrderID, OD.ProductID, OD.UnitPrice, OD.Quantity };
gv1.DataSource = query.ToArray();
gv1.DataBind();
myDebug.WriteLine(query.ToString());
//SELECT [t0].[OrderID], [t1].[ProductID] AS [ProductID], [t1].[UnitPrice] AS [UnitPrice], [t1].[Quantity] AS [Quantity]
//FROM [dbo].[Orders] AS [t0]
//LEFT OUTER JOIN [dbo].[Order Details] AS [t1] ON [t0].[OrderID] = [t1].[OrderID]
//WHERE [t0].[OrderID] = @p0
}