LINQ TO SQL 是.NET Framework 3.5 版的一個組件,提供了用於將關系數據作為對象管理的運行時基礎結構。在LINQ to SQL 中,關系數據庫的數據模型映射到用開發人員所用的編程語言表示的對象模型。當應用程序運行時,LINQ to SQL 會將對象模型中的語言集成查詢轉換為SQL,然後將它們發送到數據庫進行執行。摘自《MSDN》。
在關系數據庫中,兩個表之間的關聯關系有三種情況:一對一關系,一對多關系,多對多關系。本系列對上述各種關系演示Linq To SQL如何實現。
本文以NORTHWND數據庫為例,NORTHWND為SQL Server自帶的事例數據,如果你沒有安裝,請在此下載:,本系列級文章的工程文件在此下載:
一對多的Ling To SQL的級聯操作實現
以NORTHWND數據庫為例,NORTHWND為SQL Server自帶的事例數據:
圖1.2
如圖所示,Order和Order_Details為一對多的關系,Ling TO SQL如何實現級聯操作的?
1.級聯新增
所謂級聯新增,就是對於一個為持久化的對象,在作持久化的時候,其子對象也被持久化。
如下代碼:
protected void btnCascadeAdd_Click(object sender, EventArgs e)
{
DataClasses2DataContext db = new DataClasses2DataContext();
Orders p = new Entiy.Orders();
p.ShipCountry = "China";
p.CustomerID = "ALFKI";
p.EmployeeID = 1;
p.ShipVia = 1;
for (int i = 1; i < 5; i++)
{
Order_Details d = new Order_Details();
d.Discount = 0.2f;
d.Quantity = Convert.ToInt16(i);
d.ProductID = i;
//加入訂單明細子對象
p.Order_Details.Add(d);
}
db.Orders.InsertOnSubmit(p);
db.SubmitChanges();
}
用SQL ProFiler跟蹤如下:
用查詢分析器分析,我們可以看到Linq To SQL 支持這樣的級聯操作。
是否你懷疑這個級聯操作的事務性那?好,我們做個試驗:在頁面上新加一個button,觸發以下代碼:
protected void btnCascadeAddIsTran_Click(object sender, EventArgs e)
{
DataClasses2DataContext db = new DataClasses2DataContext();
Orders p = new Entiy.Orders();
p.ShipCountry = "MyChina";
p.CustomerID = "ALFKI";
p.EmployeeID = 1;
p.ShipVia = 1;
for (int i = 75; i < 80; i++)
{
Order_Details d = new Order_Details();
d.Discount = 0.2f;
d.Quantity = Convert.ToInt16(i);
d.ProductID = i;
//加入訂單明細子對象
p.Order_Details.Add(d);
}
db.Orders.InsertOnSubmit(p);
db.SubmitChanges();
}
大家看到,代碼和上一個有什麼不同? for (int i = 75; i < 80; i++),i的取值范圍變大,導致 Order_Details對象的關聯對象Product的ID范圍有一部分違反約束。執行後,很熟悉經典的錯誤信息:
如果你懷疑這種操作的事務性,執行如下語句:
select * from Orders where shipcountry='Mychina' select * from [Order Details]
where OrderID in (select orderid from Orders where shipcountry='Mychina'),如下圖:
請相信微軟。
2.級聯更新
對於持久化過的對象,對其屬性和其子對象的屬性進行更改,提交數據的庫的時候,Ling To SQL 會自動檢索型相關變動做出智能處理。
在頁面上新建一個button,觸發以下代碼:
protected void btnCascadeUpdate_Click(object sender, EventArgs e)
{
DataClasses2DataContext db = new DataClasses2DataContext();
Orders ord = db.Orders.Single(Q => Q.OrderID == 11120);
ord.ShipAddress = "江蘇省昆山市安博路1號安博教育集團";
for (int i = 0; i < ord.Order_Details.Count; i++)
{
//更改折扣率
ord.Order_Details[i].Discount = 0.1f;
}
db.SubmitChanges();
}
取出一個已經持久化的對象,更改其購物地址(江蘇昆山安博路1號安博教育集團)和子對象的打折率,然後Sumbit。用查詢分析器看下如下圖。不用懷疑其事務性,我已經說過:請相信微軟。
如果你想清楚Ling To SQL在這個操作中到底做了什麼事情,自己可以跟蹤下(按住Shif健,可以全部選定)如下圖。大家可以看下,Ling To SQL 生成的SQL語句相比去其它OR/M框架是很簡潔的,語言級的OR/M框架,大家不用懷疑微軟的實力。
3.級聯刪除
Ling To SQL 目前不支持級聯刪除。直接刪除會報如下錯誤:DELETE 語句與 REFERENCE 約束"FK_Order_Details_Orders"沖突。該沖突發生於數據庫"NORTHWND",表"dbo.Order Details", column 'OrderID'。
語句已終止。
那如何實現級聯刪除?既然有Order Details數據庫外建約束, 我們移除Order的子對象對象如何? page新建一個button,觸發以下事件:
protected void btnCascadeDelte_Click(object sender, EventArgs e)
{
DataClasses2DataContext db = new DataClasses2DataContext();
Orders ord = db.Orders.Single(Q => Q.OrderID == 11127);
for (int i = 0; i < ord.Order_Details.Count; i++)
{
db.Order_Details.DeleteOnSubmit(ord.Order_Details[i]);
}
db.Orders.DeleteOnSubmit(ord);
db.SubmitChanges();
}
OK,編譯,正確實現級聯刪除。
另外一種情況,只刪除Order對象的幾個字對象,然後加入新的Order Details對象,在修改Order的屬性的值,最後SubmitChanges,Ling To SQL支持這樣的操作嗎?新加一個button,執行如下操作:
protected void btnComplexOp_Click(object sender, EventArgs e)
{
DataClasses2DataContext db = new DataClasses2DataContext();
Orders ord = db.Orders.Single(Q => Q.OrderID == 11126);
//更新對象屬性
ord.ShipAddress = "昆山軟件外包實訓基地";
ord.ShipCity ="China";
//移除Order的Order_Detais第二個對象
ord.Order_Details.RemoveAt(2);
//更新Order的Order_Detais最後一個對象
Order_Details ords = ord.Order_Details.Last();
ords.Discount = 0.7f;
//加入新對象
for (int i = 10; i < 12; i++)
{
Order_Details d = new Order_Details();
d.Discount = 0.4f;
d.Quantity = Convert.ToInt16(i);
d.ProductID = i;
ord.Order_Details.Add(d);
}
db.SubmitChanges();
}
先看下執行前數據庫中的數據:
執行,爆出錯誤:
試圖刪除 Orders 和 Order_Details 之間的關系。但是,關系的其中一個外鍵 (Order_Details.OrderID) 無法設置為 null。
剛開始我們說過,在LINQ to SQL 中,關系數據庫的數據模型映射到用開發人員所用的編程語言表示的對象模型,我們去分析下我們的對象模型.
說下題外話,Ling TO SQL 創建對象模型有三種方式,一種是手工寫代碼,第二種是OR/M
對象模型編輯器,這個也是我們常用的一種,微軟提供了這個工具,被集成到IDE中,這個也是本文采用的方式。第三種是SQL Metal代碼生成器器,通常在大型數據庫(數據表非常多,關系復雜)中使用。
選擇DataClasses2.dbml文件的打開方式為XML編輯器(其實這個文件就是一個XML文件),定位到如下:
<Association Name="Orders_Order_Details" Member="Orders" ThisKey="OrderID" Type="Orders" IsForeignKey="true"/>
修改成為:
<Association Name="Orders_Order_Details" Member="Orders" ThisKey="OrderID" Type="Orders" IsForeignKey="true" DeleteOnNull="true"/>
DeleteOnNull="true" 表示在Cache允許數據孤島存在。
編譯,再執行這個操作。
大家看到,數據已經改變,和我們的操作意圖一致。