添加条件LINQ查询

问题描述:

我建立了一个NHibernate的存储库层,其中我有以下find方法:添加条件LINQ查询

public IList<TEntity> Find(Expression<Func<TEntity, bool>> query) 

我想一个条件添加到该方法中的查询。额外的条件应该将行限制在RemovedAt大于DateTime.Now的地方。

说明使用SQL:

让我们假设我有以下SQL查询:

SELECT * FROM users WHERE first_name LIKE 'a%' OR last_name LIKE 'a%' 

它看起来像这样修改后:

SELECT * FROM users WHERE (first_name LIKE 'a%' OR last_name LIKE 'a%') AND created_at > '2010-09-22 19:31' 

它可以用做linq查询,还是在nhibernate?

编辑

对不起,忘了提,所有的实体没有RemovedAt方法。接口被声明为:

public interface IRepository<TEntity, TKey> where TEntity : class, new() 

我通过查找与该名称的属性和使用反射来更新的值更改CreatedAt/RemovedAt/UpdatedAt(在各自的方法)。

首先,我不知道为什么你就是不返回的IQueryable并让该方法的用户确定他们是否想把它当作一个列表,等等。因为IQueryables不执行,直到实际需要,你可以不断加入到表达式树,直到你真的需要它。

在这种情况下,当您将其更改为对象列表时,即当查询将转换为列表时,实际上将针对数据库执行查询。

如果你真的想保持接口作为IList的,而不是一个IQueryable,只是你编译前添加一个额外的表达式表达式树。

因为我对根级表达式树的工作有限,所以我可能会给你错误的语法,所以这里是一个不同类型的例子,可能会给你足够的信息来说明我在说什么:

var query = something.Where(n => n.FirstName.StartsWith("N")) ; 
query = query.Where(n => n.created_at > DateTime.Now); 
return query.ToList(); 

我希望是有道理的。您可以继续向表达式树添加条件,直到它被编译并执行。

我仍然建议通过IQueryable的角落找寻不过,来代替。在我的示例中,您只需返回查询,而不是先调用ToList。它使得流利的语法更容易,并且在nHibernate中执行会更好,因为nHibernate会在调用数据库之前考虑所有条件。例如,如果您只需要一个累加器或一个计数,那么将在数据库中进行处理,而不是将所有行都拉回到列表中,然后遍历它以获取聚合或计数。

+0

公开IQueryable还会暴露我想在存储库类中处理的较低级别异常。无论如何,我会让服务层处理RemovedAt过滤器。 – jgauffin 2010-09-23 05:23:22

+0

对于一些额外的抽象;请看http://code.google.com/p/linq-specifications/,这可以为您提供更清晰/更统一的方法来制定查询。 – DanP 2010-09-23 11:58:42

有关他们的资料库的顶部使用Business Logic Layer与像AutoMapper一个工具将数据传输对象和实体模型之间的映射,使用Predicate BuilderLinqKit以允许沿着那些你的MVC/API控制器添加额外System.Linq.Expressions.Expression过滤器默认过滤器您设置了您的业务组件。

使用谓词构建器将允许您在将其发送到AutoMapper进行展平之前动态修改您的IQueryable,即将列表带入内存。