MEMO-LINQ DataContext對Primary Key相同物件的處理原則

今天在寫程式時,發現LINQ to SQL在管理物件上的特殊規則,做個筆記。

假設我們有一個Member資料表如下:

有一段程式,其中很取巧的用Member去承接ExecuteQuery的執行結果,前後取得四顆物件,放入一個List中: (在我的實際案例中,是SELECT另一個Table的不同欄位組裝出與Member欄位相同的結果,此處為求簡化,採SELECT '...' AS FieldName的方式模擬)

    protected void Page_Load(object sender, EventArgs e)
    {
        using (PlaygroundDataContext db = 
                            new PlaygroundDataContext())
        {
            List<Member> lst = new List<Member>();
            var m = (from o in db.Members
                     where o.UserId == 1
                     select o).First();
            lst.Add(m);
            //借用Member類別,承接ExecuteQuery的結果
            var n =
                db.ExecuteQuery<Member>(@"
                select 1 as UserId, 'Jeffrey' as UserName, 
                'ZZZ' as Code, getdate() as RegTime UNION
                select 2 as UserId, 'Ninja' as UserName, 
                'XXX' as Code, getdate() as RegTime"
                ).ToArray();
 
            lst.AddRange(n);
 
            var r = (from o in db.Members
                     where o.UserId == 2
                     select o).First();
            lst.Add(r);
 
            //猜看看,結果是什麼?
            foreach (var o in lst)
                Response.Write(
                    string.Format("<li>{0}|{1}|{2}|{3:yyyy/MM/dd HH:mm}" ,
                        o.UserId, o.UserName, o.Code, o.RegTime));
        }
 
        Response.End();
    }

大家猜看看,網頁會傳回什麼結果? X147, Jeffrey, Ninja, Darkthread? 錯!

  • 1|X147|F1|2000/01/01 00:00
  • 1|X147|F1|2000/01/01 00:00
  • 2|Ninja|XXX|2010/08/13 18:58
  • 2|Ninja|XXX|2010/08/13 18:58

由測試結果看來,在一個DataContext中,當Priimary Key相同的物件重複出現時,DataContext只會保留較早出現的那個版本。

若要避免上述物件依Primary Key自動合併及抛棄的狀況,我想到的解法是拆出不同的DataContext:

    protected void Page_Load(object sender, EventArgs e)
    {
        List<Member> lst = new List<Member>();
        using (PlaygroundDataContext db = 
                            new PlaygroundDataContext())
        {
            var m = (from o in db.Members
                     where o.UserId == 1
                     select o).First();
            lst.Add(m);
            var r = (from o in db.Members
                     where o.UserId == 2
                     select o).First();
            lst.Add(r);
        }
        using (PlaygroundDataContext db = 
                            new PlaygroundDataContext())
        {
            //借用Member類別,承接ExecuteQuery的結果
            var n =
                db.ExecuteQuery<Member>(@"
                select 1 as UserId, 'Jeffrey' as UserName, 
                'ZZZ' as Code, getdate() as RegTime UNION
                select 2 as UserId, 'Ninja' as UserName, 
                'XXX' as Code, getdate() as RegTime"
                ).ToArray();
            lst.AddRange(n);
        }
        //猜看看,結果是什麼?
        foreach (var o in lst)
            Response.Write(
                string.Format("<li>{0}|{1}|{2}|{3:yyyy/MM/dd HH:mm}",
                    o.UserId, o.UserName, o.Code, o.RegTime));
        Response.End();
    }

將ExecuteQuery隔離在另一個PlaygroundDataContext後,結果便符合我們的需求囉!

  • 1|X147|F1|2000/01/01 00:00
  • 2|Darkthread|A4|2012/12/21 00:00
  • 1|Jeffrey|ZZZ|2010/08/13 19:05
  • 2|Ninja|XXX|2010/08/13 19:05
歡迎推文分享:
Published 13 August 2010 10:18 PM 由 Jeffrey
Filed under:
Views: 8,032



意見

# xuzicn said on 18 August, 2010 11:46 PM

當Primary Key相同的物件重複出現時,DataContext只會保留較早出現的那個版本。

这个说法并不成立。我看到这个结论之后非常的惊奇,并且用你的办法试了一下,得到的结果就是预料之中的状况。不知道你的程式码是怎么写的呢?

# Jeffrey said on 19 August, 2010 02:58 AM

to xuzicn, 當真? 莫非是某個條件下才會出現此狀況? 事實上我是在實務專案上遇到離奇現象後,才回到這個簡單的LINQ to SQL的Member物件(PK = UserId, in ASP.NET 3.5)上做測試,也驗證了同樣結果(若連兩次巧合導致該文產生錯誤結論,也真算是不幸了 orz)。

不曉得可否提供更多您測試的細節(.NET 3.5 or 4.0?, EF or LINQ to SQL? 如果有程式碼示意的話更好),讓我看看是否忽略了什麼地方?

# xuzicn said on 23 August, 2010 02:59 AM

LinQ to SQL, 3.5, sql server 2005

事实上程式码已经被我扔掉了...今天重新试了一下结果正如你所写,很难琢磨清楚。

不过还是要谢谢你,至少目前知道DataContext确实不适合singleton模式

# xuzicn said on 23 August, 2010 03:02 AM

DataContext的缓存,其实很烦,只有小型的项目会考虑LinQ但是小型项目上用不上cache

普通的人当然会觉得DataContext和SqlConnection一样是一个非常expensive的,从而使用singleton或者pool,我做到一半之后才发现完全不是这么回事

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<August 2010>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication