2012-06-08 82 views
3

我正在使用一個彙編程序模式將LinqToEntity實體組裝到數據傳輸對象中,然後傳遞到客戶端層以供使用。該方法一直是將權利對象翻譯成簡化的平面對象,以提供特定於服務調用的信息。DTO和IQueryable:組裝和拆卸DTO

例如,

// Original Entity looks something like this 
public class PersonEntity 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int MotherId { get; set; } 
    public PersonEntity Mother { get; set; } 
    // lots of other properties 
} 

// Flattened DTO 
public class PersonSummaryInfo 
{ 
    public int Id { get; set; } 
    public string FullName { get; set; } 
    public string MothersFullName { get; set; } 
} 

在本例中,彙編器將創建一個PersonSummaryInfo,構建過程的FullNames一部分。

我現在面臨一些第三方控件(Telerik ASP.NET MVC GridControl)的問題,其中控件設置爲基於其Model的屬性過濾(使用IQueryable)。有一種想法似乎是你有單層設計,並將你的數據庫實體直接抽入視圖,這是我無法忍受的。

試圖將它結合到我的邏輯中,GridControl綁定到我的DTO,而不是實體,這是很好的,直到它嘗試排序任何東西。我以非常通用的方式將所有IQueryable素材都推送到我的服務中,以便爲此負責。排序嘗試進行排序,在DTO上說MothersFullName(它的行爲是將「MothersFullName」作爲字符串傳遞給您的排序邏輯),這會被推送到我的服務,通過反射嘗試對實體進行排序,利用IQueryable懶惰加載,但當然執行查詢時,會拋出一個異常,因爲「MothersFullName」不是原始實體的屬性。

是否有一個很好的策略來處理這種實現?一旦它返回到應用程序的服務層,有效地將DTO「反彙編」回到它的ORM實體是否是好的做法?或者更好地傳遞更豐富的對象,知道它們是什麼(例如,如何使用FirstName和LastName對全名進行排序)?

什麼是關鍵,我的要求是:

  • 使用花式Telerik的控制,因爲他們喜歡它的服務水平
  • 懶負載的結果(即不帶靠背2萬條記錄,並只顯示10)
  • 支持篩選,分頁等
  • 健全的體系結構實現

回答

0

走了這個解決方案。

創建包含網格特定列的sql視圖。然後使數據傳輸對象使用與View完全匹配的屬性。不是最簡單或最強有力的方式來實現這一點,但至少它可以從我的項目中獲得不需要它的數據引用。

沒有使用動態LINQ,而是保留了我的泛型方法並使用了反射來獲取匹配的列名。沒有去Telerik的開放獲取只是因爲我們已經實現了整個服務層,但它聽起來像一個很好的解決方案。 (這只是依靠開發人員來確保GridViews匹配GridViewModels屬性的屬性)。所有這些仍然是IQueryable,因此它的效率非常高。

+0

我選擇了這個作爲我的案例的答案,但我也覺得sovanesyan的答案可能適用於其他類似問題的人。 – Arkiliknam

0

你只使用RadGrid爲其開箱分類功能?我遇到了同樣的問題,最後只是使用了RadListView並在其中插入了一個尋呼機/排序器。使用該模板,您可以準確告訴它通過SortExpession屬性排序的內容。然後它只是發射正確的事件。這裏是我的事件處理程序,你可以設置任何你可以用手去觸發它。我不知道這是否是一個解決方案,但希望它可以幫助你找到一個:

protected void SortSearchTickets(object sender, RadComboBoxSelectedIndexChangedEventArgs e) 
    { 
     var selectedValue = e.Value; 
     lsvSearchResults.SortExpressions.Clear(); 
     var sortExp = new RadListViewSortExpression(); 

     switch (selectedValue) 
     { 
      case "ID": 
       sortExp.FieldName = "TicketID"; 
       break; 
      case "TicketType": 
       sortExp.FieldName = "TypeDescription"; 
       break; 
      case "Subject": 
       sortExp.FieldName = "Subject"; 
       break; 
      case "Status": 
       sortExp.FieldName = "Status.Key"; 
       break; 
      case "DueDateDesc": 
       sortExp.FieldName = "DueDate"; 
       sortExp.SortOrder = RadListViewSortOrder.Descending; 
       break; 
      case "DueDateAsc": 
       sortExp.FieldName = "DueDate"; 
       sortExp.SortOrder = RadListViewSortOrder.Ascending; 
       break; 
      case "Assigned To": 
       sortExp.FieldName = "AssignedTo.Key"; 
       break; 
      case "Assigned By": 
       sortExp.FieldName = "AssignedBy.Key"; 
       break; 
      default: 
       break; 
     } 
     lsvSearchResults.SortExpressions.AddSortExpression(sortExp); 
     lsvSearchResults.Rebind(); 
    } 
+0

在我看來,他似乎在使用ASP.NET MVC套件而不是Web表單。 – sovanesyan

4

你有一對夫婦的提前自己的選擇。首先,它確實能夠綁定到IQueryable,因爲這是最快(也是最常見)的方式來完成它,就當然的開發時間而言。

就你的情況而言(ORM頂層的完整服務層)情況有點不同。我個人建議你挖一點點,並提供custom bindings到你的網格。您可以獲得一個GridCommand對象,您可以查詢該對象進行排序和過濾,並使用該對象向服務層請求數據。這是一個很好的地方提及一個簡單的方法來解決你所面臨的問題(這是因爲你的表達式是基於DTO屬性)。您可以嘗試使用Dynamic Linq。只需從表達式構造字符串查詢並將它們傳遞給DAL。

事實上,這是Telerik的另一個產品OpenAccess ORM提出的最佳實踐。 OpenAccess SDK包含一些示例(尤其是WCF Plain服務),它們使用與您相似的體系結構。該產品還提供了一個提供整個服務層的code generation tool

+0

我現在正在使用自定義綁定並使用GridCommand對象執行所有過濾操作,但對實體模型中不存在的列進行排序或過濾時無法解決問題。我現在很可能會創建一個特定於網格的SQL視圖,並將其與一對一ViewModel一起使用,而不是從服務層中的多個實體構建自己的對象。 – Arkiliknam