DataContext
DataContext 類型(數據上下文)是 System.Data.Linq 命名空間下的重要類型,用於把查詢句法翻譯成 SQL 語句,以及把數據從數據庫返回給調用方和把實體的修改寫入數據庫。
DataContext 提供了以下一些使用的功能:
l 以日誌形式記錄 DataContext 生成的 SQL
l 執行 SQL (包括查詢和更新語句)
l 創建和刪除數據庫
DataContext 是實體和數據庫之間的橋樑,那麼首先我們需要定義映射到數據表的實體。
定義實體類
using System.Data.Linq.Mapping;
[Table (Name = "Customers" )] public class Customer { [Column (IsPrimaryKey = true )] public string CustomerID {get ; set ;}
[Column (Name = "ContactName" )] public string Name { get ; set ; }
[Column ] public string City {get ; set ;} } |
以 Northwind 數據庫爲例,上述 Customers 類被映射成一個表,對應數據庫中的 Customers 表。然後在類型中定義了三個屬性,對應表中的三個字段。其中, CustomerID 字段是主鍵,如果沒有指定 Column 特性的 Name 屬性,那麼系統會把屬性名作爲數據表的字段名,也就是說實體類的屬性名就需要和數據表中的字段名一致。
現在,創建一個 ASP.NET 頁面,然後在頁面上加入一個 GridView 控件,使用下面的代碼進行綁定數據:
using System.Data.Linq;
DataContext ctx = new DataContext ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); Table <Customer > Customers = ctx.GetTable<Customer >(); GridView1.DataSource = from c in Customers where c.CustomerID.StartsWith("A" ) select new { 顧客 ID=c.CustomerID, 顧客名 =c.Name, 城市 =c.City}; GridView1.DataBind(); |
使用 DataContext 類型把實體類和數據庫中的數據進行關聯。你可以直接在 DataContext 的構造方法中定義連接字符串,也可以使用 IDbConnection :
using System.Data.SqlClient;
IDbConnection conn = new SqlConnection ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); DataContext ctx = new DataContext (conn); |
之後,通過 GetTable 獲取表示底層數據表的 Table 類型,顯然,數據庫中的 Customers 表的實體是 Customer 類型。隨後的查詢句法,即使你不懂 SQL 應該也能看明白。從 Customers 表中找出 CustomerID 以“ A ”開頭的記錄,並把 CustomersID 、 Name 以及 City 封裝成新的匿名類型進行返回。
結果如下圖:
強類型 DataContext
public partial class NorthwindDataContext : DataContext { public Table <Customer > Customers; public NorthwindDataContext(IDbConnection connection) : base (connection) { } public NorthwindDataContext(string connection) : base (connection) { } } |
強類型數據上下文使代碼更簡潔:
NorthwindDataContext ctx = new NorthwindDataContext ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); GridView1.DataSource = from c in ctx.Customers where c.CustomerID.StartsWith("A" ) select new { 顧客 ID = c.CustomerID, 顧客名 = c.Name, 城市 = c.City }; GridView1.DataBind(); |
DataContext 其實封裝了很多實用的功能,下面一一介紹。
日誌功能
using System.IO;
NorthwindDataContext ctx = new NorthwindDataContext ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); StreamWriter sw = new StreamWriter (Server.MapPath("log.txt" ), true ); // Append ctx.Log = sw; GridView1.DataSource = from c in ctx.Customers where c.CustomerID.StartsWith("A" ) select new { 顧客 ID = c.CustomerID, 顧客名 = c.Name, 城市 = c.City }; GridView1.DataBind(); sw.Close(); |
運行程序後在網站所在目錄生成了 log.txt ,每次查詢都會把諸如下面的日誌追加到文本文件中:
SELECT [t0].[CustomerID], [t0].[ContactName], [t0].[City] FROM [Customers] AS [t0] WHERE [t0].[CustomerID] LIKE @p0 -- @p0: Input String (Size = 2; Prec = 0; Scale = 0) [A%] -- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 |
應該說這樣的日誌對於調試程序是非常有幫助的。
探究查詢
using System.Data.Common; using System.Collections.Generic;
NorthwindDataContext ctx = new NorthwindDataContext ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); var select = from c in ctx.Customers where c.CustomerID.StartsWith("A" ) select new { 顧客 ID = c.CustomerID, 顧客名 = c.Name, 城市 = c.City }; DbCommand cmd = ctx.GetCommand(select); Response.Write(cmd.CommandText + "<br/>" ); foreach (DbParameter parm in cmd.Parameters) Response.Write(string .Format(" 參數名 :{0}, 參數值 :{1}<br/>" , parm.ParameterName, parm.Value)); Customer customer = ctx.Customers.First(); customer.Name = "zhuye" ; IList <object > queryText = ctx.GetChangeSet().ModifiedEntities; Response.Write(((Customer )queryText[0]).Name); |
在這裏,我們通過 DataContext 的 GetCommand 方法獲取了查詢對應的 DbCommand ,並且輸出了 CommandText 和所有的 DbParameter 。之後,我們又通過 GetChangeSet 方法獲取了修改後的實體,並輸出了修改內容。
執行查詢
NorthwindDataContext ctx = new NorthwindDataContext ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); string newcity = "Shanghai" ; ctx.ExecuteCommand("update Customers set City={0} where CustomerID like 'A%'" , newcity); IEnumerable <Customer > customers = ctx.ExecuteQuery<Customer >("select * from Customers where CustomerID like 'A%'" ); GridView1.DataSource = customers; GridView1.DataBind(); |
前一篇文章已經說了,雖然 Linq to sql 能實現 90 %以上的 TSQL 功能。但是不可否認,對於複雜的查詢,使用 TSQL 能獲得更好的效率。因此, DataContext 類型也提供了執行 SQL 語句的能力。代碼的執行結果如下圖:
創建數據庫
testContext ctx = new testContext ("server=xxx;database=testdb;uid=xxx;pwd=xxx" ); ctx.CreateDatabase();
[Table (Name = "test" )] public class test { [Column (IsPrimaryKey = true , IsDbGenerated = true )] public int ID { get ; set ; }
[Column (DbType="varchar(20)" )] public string Name { get ; set ; } }
public partial class testContext : DataContext { public Table <test > test; public testContext(string connection) : base (connection) { } } |
這段代碼在數據庫中創建了名爲 testdb 的數據庫,等同於下面的腳本:
CREATE TABLE [dbo]. [test]( [ID] [int] IDENTITY ( 1, 1) NOT NULL, [Name] [varchar]( 20) COLLATE Chinese_PRC_CI_AS NULL, CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED ( [ID] ASC ) WITH ( IGNORE_DUP_KEY = OFF ) ON [PRIMARY] ) ON [PRIMARY] |
同時, DataContext 還提供了 DeleteDatabase() 方法,在這裏就不列舉了。
使用 DbDataReader 數據源
using System.Data.SqlClient;
var conn = new SqlConnection ("server=xxx;database=Northwind;uid=xxx;pwd=xxx" ); var ctx = new DataContext (conn); var cmd = new SqlCommand ("select * from customers where CustomerID like 'A%'" , conn); conn.Open(); var reader = cmd.ExecuteReader(); GridView1.DataSource = ctx.Translate<Customer >(reader); GridView1.DataBind(); conn.Close(); |
你同樣可以選擇使用 DataReader 獲取數據,增加了靈活性的同時也增加了性能。
看到這裏,你可能會覺得手工定義和數據庫中表對應的實體類很麻煩,不用擔心, VS2008 提供了自動生成實體類以及關係的工具,工具的使用將在以後講解。今天就講到這裏,和 DataContext 相關的事務、加載選項、併發選項以及關係實體等高級內容也將在以後講解。