天天看點

Entity Framework快速入門--一對零到一關系處理Entity Framework快速入門--索引貼

很久不更新blog了,正好趁着端午節的空,把之前一段時間使用關于EF以及工作上經驗總結一下。

此文将跟朋友們分享一下關于1對0..1實體模型一些使用包括基本的添加和查詢的注意事項。

首先我們EDMX實體模型:

Entity Framework快速入門--一對零到一關系處理Entity Framework快速入門--索引貼

模型很簡單,一個使用者的實體,另外關聯了一個使用者資訊的實體。有些情況下我們會有這樣的需求,使用者登入身份驗證,而每次再查詢使用者資訊的時候,往往會去查詢使用者表,而這時候我們僅僅使用了2-3個字段也就是使用者賬号跟密碼是否一緻,如果一緻就傳回true,否則傳回false,而我們往往在使用者表上挂在很多的其他字段,這樣就造成了無謂的性能損失。當然如果通路量很小的話,那也無所謂了。  有時候我們會把一些可以為null或者經常不使用的字段放到一張UserInfo表中,而頻繁通路和驗證的使用者表單獨出一個小的表,用于專門來進行身份驗證等業務。如上圖EDMX的設計,當然隻是一個模拟的例子。

根據這個1對0到1的關系,我們自己猜一下也能想到,那就我們在進行将使用者資訊持久化到資料庫時,使用者資訊表實體(UserInfo)必須挂在到一個User實體上才能持久化到資料庫。而User表不受UserInfo表的影響,可以單獨插入一條資料。看下面代碼都是可以正确執行:

單獨插入User實體資料:

static void InsertData()

{

using (CompanyContainer companyContainer = new CompanyContainer())

User user = new User();

user.Code = "flydragon";

user.Name = "飛龍天驚";

user.Password = "haha";

companyContainer.User.AddObject(user);

companyContainer.SaveChanges();

}

我們也可以同時儲存一個整體的資料,如下代碼所示:插入User+UserInf實體兩個資料

static void InsertFullData()

user.Code = "flydragon3";

user.Name = "飛龍天驚3";

user.Password = "haha3";

UserInfo userInfo = new UserInfo();

userInfo.Email = "[email protected]";

userInfo.Address = "北京上地";

userInfo.Phone = "110";

userInfo.User = user;

userInfo.Rmark = "";

companyContainer.UserInfo.AddObject(userInfo);

上面沒什麼好說的,也沒什麼好主意的點。當然在項目中還是遇到了很多細節的問題。當然比較頭疼的一個問題就是1對0...1關系模型資料的查詢異常的BUG。我們在查詢User實體資料的時候,EF幫我們生成的SQL腳本卻自動的幫我們對UserInfo表進行Left Out Join。很多情況我們隻檢索了User表的資料,卻也進行了Join的操作,這樣使我們本來為了提高使用者表資料查詢的效率反而進行了Join,資料量成了兩個表的笛卡爾積的結果裡進行查詢,這樣效果肯定不好。看下面代碼以及SqlProfile追蹤到的SQL:

static void Main(string[] args)

CompanyContainer companyContainer = new CompanyContainer();

var result = companyContainer.User.Where<User>(u => u.Code == "flydragon3")

.Where<User>(u => u.Password == "haha3")

.FirstOrDefault<User>();

if (result != null)

Console.WriteLine(result.Name);

Console.ReadKey();

下面是用SQLProfile工具追蹤到的執行的SQL腳本:

Entity Framework快速入門--一對零到一關系處理Entity Framework快速入門--索引貼

很明顯我們看到的是有User表和UserInfo表的Join操作。我猜測EF内部實作的細節可能是初始化User實體的時,由于導航屬性UserInfo的關系是1 對0..1做了特殊處理,也将UserInfo的資料取出來初始化了導航屬性UserInfo。

這個需要大家使用EF時候一定注意這個細節。

那我們怎樣避免這樣的結果呢:

下面幾種方式是可以杜絕這種外連接配接的:

如:

.Where<User>(u => u.Password == "haha3").Count();

Console.WriteLine(result);

對應産生的SQL為:

SELECT

[GroupBy1].[A1] AS [C1]

FROM ( SELECT

COUNT(1) AS [A1]

FROM [dbo].[User] AS [Extent1]

WHERE (N'flydragon3' = [Extent1].[Code]) AND (N'haha3' = [Extent1].[Password])

) AS [GroupBy1]

另外怎麼隻查詢User,并将User表的幾個字段取出方法如下:

.Select(u => new { Id=u.Id,Name = u.Name }).FirstOrDefault();

最終生成的SQL腳本為:

SELECT TOP (1)

[Extent1].[Id] AS [Id],

[Extent1].[Name] AS [Name]

暫時總結到這裡,寫文章真是費時費力!希望大家都分享自己的知識,大家一起交流一起進步!祝大家端午快樂!