2010-05-07 32 views
14

根據我的經驗構建Web應用程序,我一直使用n層方法。從數據庫獲取數據並填充對象的DAL,以及從DAL獲取對象並執行其所需的任何業務邏輯的BLL,以及從BLL顯示數據的網站。 我最近開始學習LINQ,並且大多數示例都顯示了從Web應用程序代碼隱藏中發生的查詢(可能我只看到了過分簡化的示例)。在n層架構中,這一直被認爲是一個很大的禁忌。
我有點不確定如何構建一個新的Web應用程序。我一直在使用VS2008中的服務器資源管理器和dbml設計器來創建dbml和對象關係。這似乎有點我不清楚,如果DBML將被認爲是DAL層,如果網站要調用一個BLL,然後會做LINQ查詢等中的方法
什麼是一些通用架構的最佳實踐,或者接近使用LINQ to SQL創建Web應用程序解決方案?LINQ to SQL Web應用程序最佳實踐

回答

16

恐怕你確實看到過分簡化的例子。 LINQ to SQL(System.Data.Linq)是您的DAL層。 L2S生成的類是您的域(但不要與Domain-Driven Design混淆)。最重要的是,您仍然可以編寫業務層。

我總是儘量防止泄漏的LINQ to SQL DataContext到演示層(你的web應用程序)。所以它不應該能夠創建或提交DataContext。您也不應將IQueryable<T>對象返回到表示層。 IMO業務層應該完全控制DataContext(工作單元)的生命週期以及SQL查詢的形狀。

但是,有幾種口味。有些人試圖放鬆這些限制。其他人甚至更進一步。這取決於你自己的口味和應用程序的大小。應用程序越大,添加抽象層的理由就越多。

當不允許IQueryable S和其他數據離開業務層相關的東西,你最終會遇到一些有趣的挑戰。例如,表示層必須指示業務層如何對結果進行排序。雖然您可以讓表示層自行對結果進行排序,但這意味着您必須從表示層獲取數據庫和頁面的所有數據,這會導致系統性能很差。這個問題有幾種解決方案。在所有情況下,您都需要通知業務層如何爲您分類結果。當您搜索LINQ dynamic sort時,可在此處找到解決方案。我自己寫了這樣一個解決方案,here

,從離開你的BL會帶來不允許IQueryable是另一個挑戰是,也域對象往往不能離開你的BL。大多數LINQ to SQL域對象將包含延遲加載的屬性(例如,對其他域對象的集合)。但是,如果DataContext處於業務層的控制之下,那麼它將在您將結果返回到表示層之前進行處置。當演示文稿比訪問延遲加載的屬性時,將發生異常,因爲DataContext已被處置。當您在業務層中處理DataContext時,此行爲當然是「按設計」。允許表示層獲得延遲加載屬性意味着BL失去對發送到數據庫的查詢的控制權,從而失去對性能的控制。

要解決此問題,您應該將BL中的數據傳輸對象(DTO)返回到表示層。 DTO將只包含數據和內部DataContext,並且沒有延遲加載的屬性。 DTO可以根據實際需求進行特殊格式化。 DTO當然會導致編碼開銷,因此係統的大小和性能需求必須證明它是正確的。爲了讓自己更容易,我傾向於將靜態投影方法放在DTO上。雖然這不符合separation of concerns原則,但我認爲它是一個非常實用的解決方案。看看例如在此CustomerDTO:

public class CustomerDTO 
{ 
    public int CustomerId { get; set; } 
    public string Name { get; set; } 
    // City is flatterned from Address.City. 
    public string City { get; set; } 

    internal static IQueryable<CustomerDTO> AsDTO(IQueryable<Customer> customers) 
    { 
     return 
      from customer in customers 
      select new CustomerDTO() 
      { 
       CustomerId = customer.Id, 
       Name = customer.Name, 
       City = customer.Address.City 
      }; 
    } 
} 

這DTO限定了內部AsDTO方法,這是能夠Customer域對象的集合轉換成的CustomerDTO DTO的集合。這使得將域對象轉換爲DTO更容易。看看例如在此BL方法:

public static CustomerDTO[] GetCustomersByCountry(string country) 
{ 
    using (var db = ContextFactory.CreateContext()) 
    { 
     IQueryable<Customer> customers = 
      (from customer in db.Customers 
      where customer.Address.Country == country 
      orderby customer.Name, customer.Id); 

     return CustomerDTO.AsDTO(customers).ToArray(); 
    } 
} 

這種方法的好處是,當你在SQL查詢,你會看到只有客戶ID,名稱和城市地址表會從數據庫中檢索。這是因爲AsDTO方法將一個IQueryable轉換爲另一個,允許LINQ to SQL在數據庫中執行整個操作。

我希望這給你一些你可以做的想法。當然,這是我對這個問題的看法,以及我在我的情況下發現的事情。

+0

感謝您的徹底迴應。我很害怕在表現層做數據訪問。我傾向於在數據層上進行大部分的排序操作,這不會成爲問題。我以前沒有聽說過DTO,聽起來像是要進一步研究的東西。 – derek 2010-05-07 22:37:51

+0

DTO經常被認爲有很多開銷。在通過線路發送數據時(例如,在使用WCF或ASMX Web服務時),它們特別有用。例如,當您閱讀Dino Esposito的「Microsoft .NET:爲企業構建應用程序」時,您會注意到Dino認爲,當您在相同AppDomain的各個層之間傳輸對象時,他們通常會付出很多開銷。儘管他對此有所瞭解,但我仍然發現它們在該特定場景中非常有用,並且我發現技術改進時開銷會變得更小...... – Steven 2010-05-08 16:11:54

+0

例如,新的C#語言構造(如自動屬性)可以更輕鬆地定義DTO和一個重構工具,如重構! Pro允許從LINQ查詢中的匿名類型定義自動生成DTO。 – Steven 2010-05-08 16:12:36

4

的LINQ to SQL是在DAL執行DB訪問,如果你想DAL和BLL之間分開。如果您的Web應用程序不太複雜(也從不打算切換數據庫後端),那麼您可以在沒有顯式DAL/BLL的情況下離開,並在代碼背後做所有事情。 LINQ to SQL對於只讀操作非常適用,但感覺實現寫操作需要多一點工作。

相關問題