2010-02-02 26 views
1

我認爲也許最初的問題太冗長了太多不必要的細節,所以這是我嘗試簡化。凌駕於LINQ to SQL的實體緩存/變更跟蹤行爲

我在尋找一種方式來執行任何下面的操作。我只需要做一個,而不是全部。如果有人知道其中一個答案,請回復。那麼,是不是可以做到以下任何在LINQ to SQL:通過ExecuteQueryExecuteMethodCall

  • 拉實體出的DataContext無需這些實體的跟蹤?

  • 調用ExecuteQueryExecuteMethodCall並保證我總是收到從數據庫中檢索到的結果的新副本,即使這些實體已經被檢索並且已經在身份緩存中?

  • 指示Linq to SQL不要執行任何跟蹤特定實體類型的更改 - 但仍允許更改跟蹤其他類型?

限制:

  • Refresh方法是不可能的;實體的數量非常大,這將成爲一場表演災難。

  • 我不能簡單地設置ObjectTrackingEnabledfalse,因爲DataContext不允許設置回true查詢執行後,我需要做一些實體進行跟蹤。

  • 我也不能扔掉原來DataContext並使用一個新的;我需要能夠在交易中做到這一點。


這已經開始成爲一個嚴重的問題,我真的覺得默認的行爲是居心不良。如果我執行即席查詢或存儲過程,我期望我收到的結果是由查詢返回的確切結果。它只有道理;如果我想要舊的,陳舊的實體,爲什麼我會回到數據庫來獲取它們?

目前,我的解決方法是(a)專門爲查詢創建新的DataContext並覆蓋事務隔離級別,或者(b)使返回類型成爲與實體中的實體相同的「DTO」每種方式但沒有[Table]屬性,並使用AutoMapper將其映射到原始實體。這兩個看起來像可怕的黑客。

真的很感謝任何人在這個難題中提出的建議。

回答

3

我設法爲此問題提出了一個可行的長期解決方法。這並不是完美的理想,但迄今爲止使用起來相對來說比較輕鬆,而且遠沒有替代品那麼可怕。

由於這些查詢都是純SQL,無論如何 - 它們全部是內聯SQL的ExecuteQuery或存儲過程的全部ExecuteMethodCall - 我決定只是下載到「原始」ADO.NET實例,當我不想要DataContext瞭解某些實體。

當然,要處理一大堆IDbCommand實例和IDataReader的手動映射是非常可怕的,所以我今天早上花了幾個小時編寫一個庫來完成大部分繁重的工作,爲IDbCommand使用IDbCommand自動LinqDataReaderMapper使用MetaModel「流利」(我使用術語鬆散)包裝,因此我可以使用我的現有實體沒有修改,以及一堆重載的擴展方法,以便更快地編寫更簡單的查詢。

在一天結束的時候,我寫這樣的事情:

var results = context.Connection 
    .Command("SELECT Column1, Column2 FROM Table " + 
      "WHERE FilterColumn1 = @Param1 AND FilterColumn2 = @Param2") 
    .Parameters(
     p => p.Name("Param1").Value(someValue), 
     p => p.Name("Param2").Value(someOtherValue)) 
    .ExecuteReader() 
    .MapWith(context.Mapping).To<MyEntity>(); 

或者只是這樣的:

var results = context 
    .ExecuteQueryRaw<MyEntity>(CommandType.StoredProcedure, "SomeProc", 
     new { Param1 = someValue, Param2 = someOtherValue }); 

我沒有要發佈的完整代碼吧 - 這很長,我認爲這只是一個大的tl; dr在這一點上 - 但主要想法是,這些都給我回IEnumerable<MyEntity>,並且因爲他們直接從IDataReader複製,他們本質上分離的實體 - DataContext對它們沒有直接的瞭解,因此既不能攔截結果,也不能在事後跟蹤結果。

所以,問題部分解決了,雖然如果我可以讓DataContext表現自己,它仍然會更好。

0

如果您從LINQ查詢爲結果構建新對象,它將不會被更改跟蹤。所以,你可以使用現有的DataContext加載你知道你值不會需要更新,像這樣(從here代碼):

using (NorthwindDataContext context = new NorthwindDataContext()) 
{ 
    var a = from c in context.Categories 
    select new Category 
    { 
    CategoryID = c.CategoryID, 
    CategoryName = c.CategoryName, 
    Description = c.Description 
    }; 
} 

我認爲這基本上是你有什麼在你的答案的第二個例子,我只是想確認這是有效的,並不是一個壞主意。

此外,我的理解是,你不應該在任何情況下使用一個巨大的DataContext;一個DataContext實際上是一個工作單元級別的集合,而不是整個世界。因此,爲您的只讀類型數據和可更新數據使用單獨的DataContexts是非常有意義的(除非您無法預測哪個是預先提供的,我想)。

+0

感謝您的回答。事務真的是一個單一的工作單元,在中間使用一個單獨的'DataContext'會導致DTC升級。從列數據創建新對象是一個很好的觀點,但不幸的是,從數據庫中檢索到的原始實體仍然被緩存 - 這只是對未跟蹤的副本所做的更改,所以它不能解決過時問題數據問題。 – Aaronaught 2010-02-05 21:23:31

+0

是的,我明白你的意思是宣傳DTC的意思;這有點痛苦。你的方法似乎可能是目前唯一可行的路線。 – technophile 2010-02-05 21:33:39