2010-05-07 93 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对于只读操作非常适用,但感觉实现写操作需要多一点工作。

相关问题