gpt4 book ai didi

linq-to-sql - 你如何使用 LinqToSQL/ Entity Framework /NHibernate 实现管道和过滤器模式?

转载 作者:行者123 更新时间:2023-12-04 17:14:12 32 4
gpt4 key购买 nike

在通过 DAL Repository 构建时,我偶然发现了一个叫做管道和过滤器的概念。我读过它here ,在这里看到了来自 here 的截屏视频.我仍然不确定如何实现这种模式。理论上一切听起来都不错,但我们如何在企业场景中真正实现这一点?

如果您在问题中提到的数据映射器/ORM 的上下文中对此模式有任何资源、提示或示例,我将不胜感激。

提前致谢!!

最佳答案

最终,LINQ 上 IEnumerable<T>是一个管道和过滤器实现。 IEnumerable<T>是一个流 API - 意味着数据在你要求时延迟返回(通过迭代器块),而不是一次加载所有内容,并返回一个大的记录缓冲区。

这意味着您的查询:

var qry = from row in source // IEnumerable<T>
where row.Foo == "abc"
select new {row.ID, row.Name};

是:
var qry = source.Where(row => row.Foo == "abc")
.Select(row = > new {row.ID, row.Name});

当您对此进行枚举时,它将懒惰地消耗数据。您可以通过 Jon Skeet 的 Visual LINQ 以图形方式看到这一点.唯一破坏管道的是强制缓冲的东西; OrderBy , GroupBy等。对于大量工作,Jon 和我自己在 Push LINQ 上工作用于在这种情况下进行聚合而无需缓冲。
IQueryable<T> (被大多数 ORM 工具暴露 - LINQ-to-SQL、 Entity Framework 、LINQ-to-NHibernate)是一个稍微不同的野兽;因为数据库引擎将完成大部分繁重的工作,所以大部分步骤可能已经完成 - 剩下的就是消耗 IDataReader并将其投影到对象/值 - 但这通常仍然是管道( IQueryable<T> 实现 IEnumerable<T> ),除非您调用 .ToArray() , .ToList()等等。

关于在企业中使用... my view就是可以用 IQueryable<T>在存储库内编写可组合查询,但它们不应该离开存储库 - 因为这会使存储库的内部操作受调用者的影响,因此您将无法正确进行单元测试/配置文件/优化等。我'已经开始在存储库中做一些聪明的事情,但返回列表/数组。这也意味着我的存储库不知道实现。

这是一种耻辱——作为“回归”的诱惑 IQueryable<T>来自存储库的方法非常大;例如,这将允许调用者添加分页/过滤器/等 - 但请记住,他们尚未实际使用数据。这使得资源管理变得痛苦。此外,在 MVC 等中,您需要确保 Controller 调用 .ToList()或类似的,因此它不是控制数据访问的 View (否则,您将无法正确地对 Controller 进行单元测试)。

在 DAL 中安全 (IMO) 使用过滤器将是这样的:
public Customer[] List(string name, string countryCode) {
using(var ctx = new CustomerDataContext()) {
IQueryable<Customer> qry = ctx.Customers.Where(x=>x.IsOpen);
if(!string.IsNullOrEmpty(name)) {
qry = qry.Where(cust => cust.Name.Contains(name));
}
if(!string.IsNullOrEmpty(countryCode)) {
qry = qry.Where(cust => cust.CountryCode == countryCode);
}
return qry.ToArray();
}
}

在这里,我们即时添加了过滤器,但在我们调用 ToArray 之前什么也没有发生。 .此时,获取并返回数据(处理过程中的数据上下文)。这可以完全单元测试。如果我们做了类似的事情但刚刚返回 IQueryable<T> ,调用者可能会执行以下操作:
 var custs = customerRepository.GetCustomers()
.Where(x=>SomeUnmappedFunction(x));

突然之间,我们的 DAL 开始失败(无法将 SomeUnmappedFunction 转换为 TSQL 等)。不过,您仍然可以在存储库中做很多有趣的事情。

这里唯一的痛点是它可能会促使您使用一些重载来支持不同的调用模式(带/不带分页等)。直到 optional/named parameters到了,我发现这里最好的答案是在界面上使用扩展方法;这样,我只需要一个具体的存储库实现:
class CustomerRepository {
public Customer[] List(
string name, string countryCode,
int? pageSize, int? pageNumber) {...}
}
interface ICustomerRepository {
Customer[] List(
string name, string countryCode,
int? pageSize, int? pageNumber);
}
static class CustomerRepositoryExtensions {
public static Customer[] List(
this ICustomerRepository repo,
string name, string countryCode) {
return repo.List(name, countryCode, null, null);
}
}

现在我们在 ICustomerRepository 上有了虚拟重载(作为扩展方法) - 所以我们的来电者可以使用 repo.List("abc","def")无需指定分页。

最后 - 没有 LINQ,使用管道和过滤器会变得更加痛苦。您将编写某种基于文本的查询(TSQL、ESQL、HQL)。您显然可以附加字符串,但它不是非常“管道/过滤器”-ish。 “Criteria API”要好一些 - 但不如 LINQ 优雅。

关于linq-to-sql - 你如何使用 LinqToSQL/ Entity Framework /NHibernate 实现管道和过滤器模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/679027/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com