我正在为nhibernate构建一个存储库层,其中我有以下find方法:
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(在各自的方法中)。
答案 0 :(得分:2)
首先,我不确定为什么你不返回IQueryable并让方法的用户确定他们是否想要它作为List等。因为IQueryables直到实际需要才被执行,你可以继续添加到表达式树,直到你真正需要它。
在这种情况下,当您将其更改为对象列表时,即当数据库变为列表时,实际上将对数据库执行查询。
如果你真的想将接口保持为IList而不是IQueryable,只需在编译之前向表达式树添加一个额外的表达式。
由于我对根级别表达式树的工作有限,我可能会给你错误的语法,所以这里有一个不同类型的例子可能会给你足够的信息来说明我在说什么:
var query = something.Where( n => n.FirstName.StartsWith("N")) ;
query = query.Where(n => n.created_at > DateTime.Now);
return query.ToList();
我希望这是有道理的。您可以继续向表达式树添加条件,直到它被编译和执行。
我仍然建议传递arround IQueryable。在我的示例中,您只需返回查询而不是先调用ToList。它使得流畅的语法更容易,并且使用nHibernate会更好地执行,因为nHibernate会在调用数据库之前尝试将所有条件考虑在内。例如,如果您只需要一个aggragate或count,那么将在数据库中处理,而不是将所有行拉回到列表中,然后迭代它以获得聚合或计数。
答案 1 :(得分:0)
对于那些在其资源库顶部使用Business Logic Layer以及AutoMapper之类的工具在数据传输对象和实体模型之间进行映射的人,请使用Predicate Builder中的LinqKit来允许您的MVC / API控制器向您在业务组件上设置的默认过滤器添加其他System.Linq.Expressions.Expression
过滤器。
使用谓词构建器可以动态修改IQueryable
,然后再将其发送到AutoMapper进行展平,即将列表放入内存。