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

der*_*rek 14 linq asp.net n-tier-architecture linq-to-sql

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

Ste*_*ven 16

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

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

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

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

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

要解决此问题,您应该将数据传输对象(DTO)从BL返回到表示层.DTO将只包含数据而没有内部DataContext,也没有延迟加载的属性.可以针对手头的实际请求特别格式化DTO.DTO当然会导致编码开销,因此系统的大小和性能需求必须证明它是合理的.为了让自己更容易,我倾向于在DTO上放置静态投影方法.虽然这不符合关注点分离原则,但我认为这是一个非常实用的解决方案.请查看此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
            };
    }
}
Run Code Online (Sandbox Code Playgroud)

此DTO定义了一个内部AsDTO方法,该方法能够将 Customer域对象的集合转换为CustomerDTODTO 的集合.这使得域对象到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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是,当您查看SQL查询时,您将看到将只从数据库中检索客户ID,名称和地址表的城市.这是因为该AsDTO方法将一个转换IQueryable为另一个,允许LINQ to SQL在数据库中执行总操作.

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