2013-03-12 56 views
0

我正在使用telerik的OpenAccess ORM,並且正在對生成的代碼進行一些更改。對於具有導航性能(一鍵到另一個表)的實體,這些都爲ILists像下面這樣產生:IList在什麼時候導致查詢在ORM中執行?

private IList<SystemUser> _SystemUsers = new List<SystemUser>(); 
public virtual IList<SystemUser> SystemUsers 
{ 
    get 
    { 
     return this._SystemUsers; 
    } 
} 

首先,在什麼點SystemUsers實際上對數據庫查詢?這是一個IList,所以我會認爲這將針對創建對象的數據庫執行,但我知道情況並非如此。

我想要做的是過濾掉刪除的項目在所有我生成的導航性能,我一直在更改T4模板用下面的代碼來做到這一點:

private IList<SystemUser> _SystemUsers = new List<SystemUser>(); 

public virtual IList<SystemUser> SystemUsers 
{ 
    get 
    { 
     if (!Entities.IncludeDeletedEntities) 
     { 
      var currentContext = Entities.GetContext(this); 
      ContextChanges changes = currentContext.GetChanges(); 
      IList<SystemUser> deletedItems = changes.GetDeletes<SystemUser>(); 
      return this._SystemUsers.Except(deletedItems).ToList(); //Question is here 
     } 

     return this._SystemUsers; 
    } 
} 

本質上講,這只是返回收集減去標記爲刪除的那些。我關心的是.ToList()以及它何時執行。每次訪問SystemUsers時,我都不想通過導致ToList()與數據庫進行查詢來減慢查詢速度,但我也想篩選我的項目。我甚至不確定這個ToList()會導致數據庫命中。我不確定代碼何時會實際到達數據庫,所以我正在尋找一些幫助/提示來過濾掉我的已刪除項目,而不會觸及數據庫,直到我在代碼中使用SystemUsers通過添加更多的過濾器(where子句等)。

回答

0

我不知道OpenAccess,但我認爲大致相同的原則適用於實體框架。在那個背景下,我只看到你的代碼的主要問題。

第一個反對意見是從架構的角度出發的。你的實體對象不應該知道上下文的存在。

其他異議是技術性的。

  • 正如您已經指出,您的代碼將在每次SystemUsers被解決時執行。 ToList()將始終導致數據庫命中。我不知道如果您刪除ToList()會發生什麼情況,這取決於GetChangesGetDeletes做了什麼。我不知道。但至少它會在每次枚舉SystemUsers時導致額外的數據庫命中。

  • 我假設,就像EF一樣,OpenAccess也支持標記爲virtual的集合的延遲加載。可能它會創建一個從實體類型派生的代理類型,併爲導航屬性添加接線以實現延遲加載。由於該屬性只有一個getter,我假設OpenAccess通過Add填充了一個集合。這導致各種副作用:

    1. 這將意味着基本屬性訪問(運行查詢)每次項目添加到它。
    2. 您的代碼將返回一個臨時列表。任何添加的項目將在下次您解決該屬性時消失!該集合將永遠不會被填充。
  • 最後,當您的對象正在物化時打開第二個閱讀器時,可能會導致不可預知的行爲。

所以我覺得你應該是有或沒有被標記爲刪除的那些返回實體倉庫解決軟刪除的問題。或者,也許你可以創建一個計算(未映射)的屬性,返回沒有「已刪除」的SystemUsers。

+1

你說得很好。我想我會停止走下那條危險的道路。 – Justin 2013-03-12 14:34:33

1

我不能確定地說Telerik工具,但會懷疑它們有點類似於EF和LINQ to SQL,它們在調用GetEnumerator(由ToList在內部調用)時評估任何表達式。爲了自己測試,使用一個分析工具來確定數據庫請求的確切位置。 SQL Profiler和Intellitrace應該可用於分析。還有其他商業性能分析器可用,但我不確定Telerik Open Access有什麼功能。你可能想檢查他們的論壇。