DataContext
DataContext作為LINQ to SQL框架的主入口點,為我們 提供了一些方法和屬性,本文用幾個例子說明DataContext幾個典型的應用。
創建和刪除數據庫
CreateDatabase方法用於在服務器上創建數據庫。
DeleteDatabase方法用於刪除由DataContext連接字符串標識的數據 庫。
數據庫的名稱有以下方法來定義:
如果數據庫在連接字符串 中標識,則使用該連接字符串的名稱。
如果存在DatabaseAttribute屬性 (Attribute),則將其Name屬性(Property)用作數據庫的名稱。
如果連接 字符串中沒有數據庫標記,並且使用強類型的DataContext,則會檢查與 DataContext繼承類名稱相同的數據庫。如果使用弱類型的DataContext,則會引 發異常。
如果已通過使用文件名創建了DataContext,則會創建與該文件 名相對應的數據庫。
我們首先用實體類描述關系數據庫表和列的結構的 屬性。再調用DataContext的CreateDatabase方法,LINQ to SQL會用我們的定義 的實體類結構來構造一個新的數據庫實例。還可以通過使用 .mdf 文件或只使用 目錄名(取決於連接字符串),將 CreateDatabase與SQL Server一起使用。 LINQ to SQL使用連接字符串來定義要創建的數據庫和作為數據庫創建位置的服 務器。
說了這麼多,用一段實例說明一下吧!
首先,我們新建一 個NewCreateDB類用於創建一個名為NewCreateDB.mdf的新數據庫,該數據庫有一 個Person表,有三個字段,分別為PersonID、PersonName、Age。
public class NewCreateDB : DataContext
{
public Table<Person> Persons;
public NewCreateDB (string connection)
:
base(connection)
{
}
public NewCreateDB(System.Data.IDbConnection connection)
:
base(connection)
{
}
}
[Table(Name = "Person")]
public partial class Person : INotifyPropertyChanged
{
private int _PersonID;
private string _PersonName;
private System.Nullable<int> _Age;
public Person() { }
[Column(Storage = "_PersonID", DbType = "INT",
IsPrimaryKey = true)]
public int PersonID
{
get { return this._PersonID; }
set
{
if ((this._PersonID != value))
{
this.OnPropertyChanged("PersonID");
this._PersonID = value;
this.OnPropertyChanged ("PersonID");
}
}
}
[Column(Storage = "_PersonName", DbType = "NVarChar(30)")]
public string PersonName
{
get { return this._PersonName; }
set
{
if ((this._PersonName != value))
{
this.OnPropertyChanged ("PersonName");
this._PersonName = value;
this.OnPropertyChanged ("PersonName");
}
}
}
[Column(Storage = "_Age", DbType = "INT")]
public System.Nullable<int> Age
{
get { return this._Age; }
set
{
if ((this._Age != value))
{
this.OnPropertyChanged("Age");
this._Age = value;
this.OnPropertyChanged("Age");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged (string PropertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this,
new PropertyChangedEventArgs(PropertyName));
}
}
}
接下來的一段代碼先創建一個數據庫,在調用 CreateDatabase後,新的數據庫就會存在並且會接受一般的查詢和命令。接著插 入一條記錄並且查詢。最後刪除這個數據庫。
//1.新建一個臨時 文件夾來存放新建的數據庫
string userTempFolder = Environment.GetEnvironmentVariable
("SystemDrive") + @"\YJingLee";
Directory.CreateDirectory (userTempFolder);
//2.新建數據庫NewCreateDB
string userMDF = System.IO.Path.Combine(userTempFolder,
@"NewCreateDB.mdf");
string connStr = String.Format (@"Data Source=.\SQLEXPRESS;
AttachDbFilename={0};Integrated Security=True;
Connect Timeout=30;User Instance=True;
Integrated Security = SSPI;", userMDF);
NewCreateDB newDB = new NewCreateDB(connStr);
newDB.CreateDatabase();
//3.插入 數據並查詢
var newRow = new Person
{
PersonID = 1,
PersonName = "YJingLee",
Age = 22
};
newDB.Persons.InsertOnSubmit(newRow);
newDB.SubmitChanges();
var q = from x in newDB.Persons
select x;
//4.刪除數據庫
newDB.DeleteDatabase();
//5.刪除臨時目錄
Directory.Delete (userTempFolder);
數據庫驗證
DatabaseExists方法用於 嘗試通過使用DataContext中的連接打開數據庫,如果成功返回true。
下 面代碼說明是否存在Northwind數據庫和NewCreateDB數據庫 。
// 檢測Northwind數據庫是否存在
if (db.DatabaseExists())
Console.WriteLine("Northwind數據庫存在");
else
Console.WriteLine("Northwind數據庫不存在");
//檢測 NewCreateDB數據庫是否存在
string userTempFolder = Environment.GetEnvironmentVariable("Temp");
string userMDF = System.IO.Path.Combine(userTempFolder,
@"NewCreateDB.mdf");
NewCreateDB newDB = new NewCreateDB(userMDF);
if (newDB.DatabaseExists())
Console.WriteLine("NewCreateDB數據庫存在");
else
Console.WriteLine("NewCreateDB數據庫不存在 ");
數據庫更改
SubmitChanges方法計算要插入、更 新或刪除的已修改對象的集,並執行相應命令以實現對數據庫的更改。
無論對象做了多少項更改,都只是在更改內存中的副本。並未對數據庫中的實際 數據做任何更改。直到對DataContext顯式調用SubmitChanges,所做的更改才會 傳輸到服務器。調用時,DataContext會設法將我們所做的更改轉換為等效的SQL 命令。我們也可以使用自己的自定義邏輯來重寫這些操作,但提交順序是由 DataContext的一項稱作“更改處理器”的服務來協調的。事件的順 序如下:
當調用SubmitChanges時,LINQ to SQL會檢查已知對象的集合 以確定新實例是否已附加到它們。如果已附加,這些新實例將添加到被跟蹤對象 的集合。
所有具有掛起更改的對象將按照它們之間的依賴關系排序成一 個對象序列。如果一個對象的更改依賴於其他對象,則這個對象將排在其依賴項 之後。
在即將傳輸任何實際更改時,LINQ to SQL會啟動一個事務來封裝 由各條命令組成的系列。
對對象的更改會逐個轉換為SQL命令,然後發送 到服務器。
如果數據庫檢測到任何錯誤,都會造成提交進程停止並引發 異常。將回滾對數據庫的所有更改,就像未進行過提交一樣。DataContext 仍具 有所有更改的完整記錄。
下面代碼說明的是在數據庫中查詢CustomerID 為ALFKI的顧客,然後修改其公司名稱,第一次更新並調用SubmitChanges()方法 ,第二次更新了數據但並未調用SubmitChanges()方法。//查詢
Customer cust = db.Customers.First(c => c.CustomerID == "ALFKI");
//更新數據並調用SubmitChanges()方法
cust.CompanyName = "YJingLee's Blog";
db.SubmitChanges();
//更新數據沒有調用SubmitChanges()方法
cust.CompanyName = "http://lyj.cnblogs.com";
動態查詢
使用動態查詢,這個例子用CreateQuery()方法創建一個 IQueryable<T>類型表達式輸出查詢的語句。這裡給個例子說明一下。有 關動態查詢具體內容,下一篇介紹。
var c1 = Expression.Parameter(typeof(Customer), "c");
PropertyInfo City = typeof(Customer).GetProperty ("City");
var pred = Expression.Lambda<Func<Customer, bool>>(
Expression.Equal(
Expression.Property(c1, City),
Expression.Constant("Seattle")
), c1
);
IQueryable custs = db.Customers;
Expression expr = Expression.Call(typeof(Queryable), "Where",
new Type[] { custs.ElementType }, custs.Expression, pred);
IQueryable<Customer> q = db.Customers.AsQueryable().
Provider.CreateQuery<Customer>(expr);
日志
Log屬性用於將SQL查詢或命令打印到TextReader。此方法對了解 LINQ to SQL 功能和調試特定的問題可能很有用。
下面的示例使用Log屬性在 SQL代碼執行前在控制台窗口中顯示此代碼。我們可以將此屬性與查詢、插入、 更新和刪除命令一起使用。
//關閉日志功能
//db.Log = null;
//使用日志功能:日志輸出到控制台窗口
db.Log = Console.Out;
var q = from c in db.Customers
where c.City == "London"
select c;
//日志輸出到 文件
StreamWriter sw = new StreamWriter(Server.MapPath ("log.txt"), true);
db.Log = sw;
var q = from c in db.Customers
where c.City == "London"
select c;
sw.Close();