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