根据我构建 Web 应用程序的经验,我一直使用 n 层方法.从数据库获取数据并填充对象的 DAL,从 DAL 获取对象并对其执行所需的任何业务逻辑的 BLL,以及从 BLL 获取它的显示数据的网站.我最近开始学习 LINQ,大多数示例都显示了从 Web 应用程序代码隐藏中发生的查询(可能我只看到了过于简化的示例).在 n 层架构中,这一直被视为一个很大的禁忌.
我有点不确定如何构建一个新的 Web 应用程序.我一直在 VS2008 中使用服务器资源管理器和 dbml 设计器来创建 dbml 和对象关系.我似乎有点不清楚 dbml 是否会被视为 DAL 层,网站是否应该调用 BLL 中的方法,然后执行 LINQ 查询等
有哪些通用的架构最佳实践或使用 LINQ to SQL 创建 Web 应用程序解决方案的方法?
In my experience building web applications, I've always used a n-tier approach. A DAL that gets data from the db and populates the objects, and BLL that gets objects from the DAL and performs any business logic required on them, and the website that gets it's display data from the BLL.
I've recently started learning LINQ, and most of the examples show the queries occurring right from the Web Application code-behinds(it's possible that I've only seen overly simplified examples). In the n-tier architectures, this was always seen as a big no-no.
I'm a bit unsure of how to architect a new Web Application. I've been using the Server Explorer and dbml designer in VS2008 to create the dbml and object relationships. It seems a little unclear to me if the dbml would be considered the DAL layer, if the website should call methods within a BLL, which then would do the LINQ queries, etc.
What are some general architecture best practices, or approaches to creating a Web Application solution using LINQ to SQL?
恐怕您确实见过过于简化的示例.LINQ to SQL (System.Data.Linq) 是您的 DAL 层.L2S 生成的类是您的域(但不要与 域驱动设计混淆).最重要的是,您仍然可以编写业务层.
I'm afraid you've indeed seen overly simplified examples. LINQ to SQL (System.Data.Linq) is your DAL layer. The classes L2S generates is your domain (but not to confuse with Domain-Driven Design). On top of that you can still write your Business Layer.
我总是试图防止将 LINQ to SQL DataContext
泄漏到表示层(您的 Web 应用程序)中.所以它不应该能够创建或提交 DataContext
.您也不应该将 IQueryable
对象返回到表示层.IMO 业务层应该完全控制 DataContext
(工作单元)的生命周期和 SQL 查询的形状.
I always try to prevent leaking the LINQ to SQL DataContext
into the presentation layer (your web app). So it shouldn't be able to create or commit a DataContext
. Neither should you return IQueryable<T>
objects to the presentation layer. IMO the business layer should have full control over the lifetime of the DataContext
(unit of work) and the shape of the SQL queries.
但是,有几种口味.有些人搭帐篷来放松这些限制.其他人甚至走得更远.这取决于您自己的口味和应用程序的大小.应用程序越大,添加抽象层就越合理.
However, there are several flavors. Some people tent to relax these constraints. Others even go much much further. It depends on your own taste and the size of the application. The bigger the application, the more it is justified to add layers of abstraction.
当禁止 IQueryable
和其他数据相关的东西离开业务层时,你最终会遇到一些有趣的挑战.例如,表示层必须指示业务层如何对结果进行排序.虽然您可以让表示层自己对结果进行排序,但这意味着您必须从表示层的数据库和页面中获取所有数据,这会导致系统性能非常差.这个问题有几种解决方案.在所有情况下,您都需要通知业务层如何为您排序结果.当您搜索 LINQ 动态排序 时,可以在此处找到解决方案.我自己写过这样的解决方案,这里.
When disallowing IQueryable
s and other data related stuff from leaving the business layer, you'll end up having some interesting challenges. For instance, the presentation layer must instruct the business layer how to sort results. While you could let the presentation layer sort the results itself, this would mean that you would have to get all data from the database and page at the presentation layer, what would lead to a very badly performing system. There are several solutions to this problem. In all cases you will need to inform the business layer how to sort the results for you. Solutions can be found here at SO when you search for LINQ dynamic sort. I've written such a solution myself, here.
禁止 IQueryable
离开您的 BL 会带来的另一个挑战是域对象通常也不能离开您的 BL.大多数 LINQ to SQL 域对象将包含延迟加载的属性(例如,其他域对象的集合).但是,当 DataContext
控制业务层时,它会在您将结果返回到表示层之前被处理掉.当演示文稿访问延迟加载的属性时,将发生异常,因为 DataContext
已经被释放.当您在业务层中处理 DataContext
时,这种行为当然是设计使然".允许表示层获得延迟加载的属性意味着 BL 失去了对发送到数据库的查询的控制,从而失去了对性能的控制.
Another challenge that disallowing IQueryable
s from leaving your BL will bring is that also domain objects can often not leave your BL. Most of your LINQ to SQL domain objects will contain lazy loaded properties (for instance, collections to other domain objects). However, when the DataContext
is in control of the Business Layer, it will be disposed, before you return results to the presentation layer. When the presentation than accesses a lazy loaded property, an exception will occur, because the DataContext
has already been disposed. When you dispose the DataContext
in your business layer, this behavior is of course 'by design'. Allowing the presentation layer to get lazy loaded properties means the BL loses control over the queries that are sent to the database, thus losing control over performance.
要解决此问题,您应该将数据传输对象 (DTO) 从 BL 返回到表示层.DTO 将只包含数据和没有内部DataContext
,并且没有延迟加载的属性.DTO 可以针对手头的实际请求进行特殊格式化.DTO 本身当然会导致编码开销,因此您的系统大小和性能需求必须证明它是合理的.为了方便我自己,我倾向于将静态投影方法放在 DTO 上.虽然这不符合 关注点分离 原则,但我认为这是一个非常实用的解决方案.以这个 CustomerDTO 为例:
To resolve this issue, you should return Data Transfer Objects (DTO) from the BL to the presentation layer. A DTO will contain just data and no internal DataContext
, and no lazy loaded properties. A DTO can be specially formatted for the actual request at hand. DTOs of course lead to coding overhead themselves, so the size of your system and the performance needs must justify it. To make it easier for myself, I tend to put static projection methods on the a DTO. While this doesn't conform to the separation of concerns principle, I foudn it to be a very practical solution. Look for instance at this 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 方法的例子:
This DTO defines an internal AsDTO
method, which is able to convert a collection of Customer
domain objects to a collection of CustomerDTO
DTOs. This makes conversion of domain objects to DTOs much easier. Look for instance at this BL method:
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 执行数据库中的全部操作.
The nice thing about this approach is that when you look at the SQL query, you'll see that only the customer Id, Name and the City of the Address table will be retrieved from the database. This is because the AsDTO
method translates one IQueryable
to another, allowing LINQ to SQL to perform the total operation in the database.
我希望这能给你一些关于你可以做什么的想法.当然,这是我对这个主题的看法以及我在我的情况下发现的实际情况.
I hope this gives some ideas of what you can do. Of course, this is my view on the subject and the things I've found practical in my situations.
这篇关于LINQ to SQL Web 应用程序最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!