Asp.net LINQ到SQL Web应用程序最佳实践

Asp.net LINQ到SQL Web应用程序最佳实践,asp.net,linq,linq-to-sql,n-tier-architecture,Asp.net,Linq,Linq To Sql,N Tier Architecture,根据我构建web应用程序的经验,我一直使用n层方法。从数据库获取数据并填充对象的DAL,从DAL获取对象并对其执行所需的任何业务逻辑的BLL,以及从BLL获取其显示数据的网站。 我最近开始学习LINQ,大多数示例都显示了从Web应用程序代码后面直接出现的查询(可能我只看到过过于简化的示例)。在n层体系结构中,这一直被视为一个大禁忌。 我有点不确定如何构建一个新的Web应用程序。我一直在使用VS2008中的服务器资源管理器和dbml设计器来创建dbml和对象关系。我似乎有点不清楚dbml是否会被视

根据我构建web应用程序的经验,我一直使用n层方法。从数据库获取数据并填充对象的DAL,从DAL获取对象并对其执行所需的任何业务逻辑的BLL,以及从BLL获取其显示数据的网站。 我最近开始学习LINQ,大多数示例都显示了从Web应用程序代码后面直接出现的查询(可能我只看到过过于简化的示例)。在n层体系结构中,这一直被视为一个大禁忌。
我有点不确定如何构建一个新的Web应用程序。我一直在使用VS2008中的服务器资源管理器和dbml设计器来创建dbml和对象关系。我似乎有点不清楚dbml是否会被视为DAL层,网站是否应该调用BLL中的方法,然后由BLL执行LINQ查询,等等。

使用LINQ to SQL创建Web应用程序解决方案的一些通用架构最佳实践或方法是什么?

如果要在DAL和BLL之间进行分离,LINQ to SQL是DAL实现中的DB访问。如果您有不太复杂的Web应用程序(也不打算切换DB后端),那么您可以不使用显式的DAL/BLL,而是在代码背后完成所有工作。LINQ to SQL对于只读操作非常有效,但对于实现写操作来说,感觉需要做更多的工作。

恐怕您确实看到过过于简化的示例。LINQtoSQL(System.Data.LINQ)是DAL层。L2S生成的类是您的域(但不要混淆)。除此之外,您仍然可以编写业务层

我总是试图防止LINQ to SQL
DataContext
泄漏到表示层(您的web应用程序)。因此,它应该不能创建或提交
DataContext
。也不应将
IQueryable
对象返回到表示层。在我看来,业务层应该完全控制
DataContext
(工作单元)的生命周期和SQL查询的形状

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

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

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

要解决此问题,应将数据传输对象(DTO)从BL返回到表示层。DTO只包含数据,不包含内部
DataContext
,也不包含延迟加载的属性。DTO可以针对手头的实际请求进行特殊格式化。DTO本身当然会导致编码开销,因此系统的大小和性能需求必须证明这一点。为了让我自己更容易,我倾向于将静态投影方法放在DTO上。虽然这不符合原则,但我认为这是一个非常实用的解决方案。例如,看看这个CustomerTo:

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
            };
    }
}
这种方法的好处是,当您查看SQL查询时,您将看到只有客户Id、名称和地址表的城市将从数据库中检索。这是因为
AsDTO
方法将一个
IQueryable
转换为另一个,允许LINQ-to-SQL在数据库中执行整个操作


我希望这能给你一些想法。当然,这是我对这个问题的看法,也是我认为在我的情况下可行的事情。

感谢您的全面回复。我对在表示层进行数据访问感到畏缩。我目前倾向于在数据层进行大部分排序,这样就不会有问题了。我以前没有听说过DTO,听起来像是需要进一步研究的东西。DTO通常被认为有很多开销。它们在跨线路发送数据时特别有用(例如,使用WCF或ASMX web服务时)。例如,当您阅读Dino Esposito的“Microsoft.NET:为企业构建应用程序”时,您会注意到Dino认为,当您在同一AppDomain的层之间传输对象时,它们通常会带来很大的开销。虽然他在这一点上是正确的,但我仍然发现它们在特定场景中很有用,而且我看到随着技术的进步,开销会越来越小……例如,新的C语言结构,如自动pr
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();
    }
}