LINQ to SQL Web应用程序最佳实践

时间:2010-05-07 00:53:19

标签: asp.net linq linq-to-sql n-tier-architecture

根据我构建Web应用程序的经验,我总是使用n层方法。从数据库获取数据并填充对象的DAL,以及从DAL获取对象并执行它们所需的任何业务逻辑的BLL,以及从BLL获取它的显示数据的网站。 我最近开始学习LINQ,大多数示例都显示了从Web应用程序代码隐藏发生的查询(我可能只看到过于简化的示例)。在n层架构中,这一直被视为一个大禁忌 我对如何构建新的Web应用程序有点不确定。我一直在VS2008中使用Server Explorer和dbml designer来创建dbml和对象关系。如果dbml被认为是DAL层,如果网站应该调用BLL中的方法,然后执行LINQ查询等,那么对我来说似乎有点不清楚。 什么是一般的体系结构最佳实践,或使用LINQ to SQL创建Web应用程序解决方案的方法?

2 个答案:

答案 0 :(得分:16)

我担心你确实看到了过于简化的例子。 LINQ to SQL(System.Data.Linq)是您的DAL层。 L2S生成的类是您的域(但不要与Domain-Driven Design混淆)。最重要的是,您仍然可以编写业务层。

我总是试图防止将LINQ to SQL DataContext泄漏到表示层(您的Web应用程序)中。所以它不应该能够创建或提交DataContext。您也不应该将IQueryable<T>个对象返回到表示层。 IMO业务层应该完全控制DataContext(工作单元)的生命周期和SQL查询的形状。

然而,有几种口味。有些人试图放松这些限制。其他人甚至走得更远。这取决于您自己的口味和应用程序的大小。应用程序越大,添加抽象层的合理性就越大。

当禁止IQueryable和其他与数据相关的内容离开业务层时,您最终会遇到一些有趣的挑战。例如,表示层必须指示业务层如何对结果进行排序。虽然您可以让表示层对结果本身进行排序,但这意味着您必须从表示层获取数据库和页面中的所有数据,这会导致系统性能非常糟糕。这个问题有几种解决方案。在所有情况下,您都需要通知业务层如何为您排序结果。当您搜索LINQ dynamic sort时,可以在此处找到解决方案。我自己写了这样一个解决方案,here

禁止IQueryable离开你的BL的另一个挑战是,域名对象通常也不会离开你的BL。大多数LINQ to SQL域对象都将包含延迟加载的属性(例如,对其他域对象的集合)。但是,当DataContext控制业务层时,在将结果返回到表示层之前,它将被处理掉。当演示文稿比访问延迟加载的属性时,将发生异常,因为DataContext已经被处理掉了。当您在业务层中处置DataContext时,此行为当然是“按设计”。允许表示层获取延迟加载属性意味着BL失去对发送到数据库的查询的控制权,从而失去对性能的控制。

要解决此问题,您应该将数据传输对象(DTO)从BL返回到表示层。 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在数据库中执行总操作。

我希望这会给你一些关于你能做些什么的想法。当然,这是我对这个主题以及我在我的情境中发现的实际情况的看法。

答案 1 :(得分:4)

如果要在DAL和BLL之间分离,LINQ to SQL是DAL实现中的DB访问。如果您的Web应用程序不那么复杂(并且也从不打算切换数据库后端),那么您可以在没有显式DAL / BLL的情况下离开并在代码中执行所有操作。 LINQ to SQL非常适合只读操作,但感觉执行写操作需要更多工作。