我在C#中有一个标准的存储库接口,它包括以下方法:
IEnumerable<T> GetAll();
T GetById(int id);
void Delete(T entity);
void Add(T entity);
在我的域层,我实例化的是一个新的工作单元包装器并将其传递给存储库。工作单元包装类隐藏我是使用NHibernate还是实体框架并公开Commit()方法。
在我的域图层中,如何查询仅满足特定条件的对象?
我认为我现在正在做的事情非常低效。我目前正在这样做:
var results = myRepository.GetAll().Where......
如果我有大量的对象,GetAll()会在过滤掉我不需要的对象之前返回它们中的每一个吗?如何防止不需要的对象被退回?
显然我可以在接口上添加更多方法,但这似乎与仅通过接口公开CRUD操作一致。
即。 - 我认为我不应该添加(但也许我错了):
IList<T> GetAllWhereMeetsMyCriteria();
答案 0 :(得分:6)
是的,您的GetAll().Where
会将所有对象从数据库中提取到您的应用程序并执行linq-to-objects。 @Kamyar解决方案也会这样做。 @Dysaster在我写这个答案时提供了正确的解决方案。
首先 - 你真的需要必须同时支持NHibernate或EF的存储库吗?是客户要求吗?如果不是,你就是在浪费资源。选择技术并创建应用程序所需的最小抽象,以便分离关注点。
如果你真的需要高级抽象和持久性API的绝对独立性,你应该使用家庭中的第三个模式 - Specification pattern。使用自定义规范,如果将规范描述的条件转换为数据源所需的操作,您将能够将持久性更改为任何内容。 NHibernate中的Criteria API或IQueryable
上的扩展方法是规范,但它们与技术有关。
答案 1 :(得分:3)
查看this blog post [weblogs.asp.net]中使用的存储库模式。我发现源代码使用了一些有趣的模式,我一直回到并再次检查。该代码实现了存储库和工作单元模式。
要回答您的具体问题,存储库界面包含以下方法:
IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
它在RepositoryBase<T>
类中实现如下:
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return dbset.Where(where).ToList();
}
EF和NHibarnate可能都具有支持此用途所需的接口。
答案 2 :(得分:2)
不熟悉nhibernate,但通常我会使用你的最后一个解决方案(IList<T> GetAllWhereMeetsMyCriteria();
):
public IList<TEntity> Find<TEntity>(Func<TEntity, bool> criteria) where TEntity : class
{
return this.Query<TEntity>().Where<TEntity>(criteria).ToList<TEntity>();
}
有一个很棒的Genric Repository,写于:http://www.martinwilley.com/net/code/nhibernate/genericrepository.html
您可能想要使用它,因为它涵盖了更多情况。此外,您可以从中派生自定义存储库以满足特定需求。 (例如:http://www.martinwilley.com/net/code/nhibernate/productrepository.html)
<强>更新强>:
您可以在派生的存储库中定义自定义标准并使用它们。例如
private ICriteria CriteriaCategoryId(int categoryId)
{
ICriteria criteria = Session.CreateCriteria(typeof(Product));
criteria.CreateCriteria("Category")
.Add(Expression.Eq("Id", categoryId));
return criteria;
}
public IList<Product> ProductByCategory(int categoryId, int pageStartRow, int pageSize)
{
var criteria = CriteriaCategoryId(categoryId)
.SetFirstResult(pageStartRow)
.SetMaxResults(pageSize);
return criteria.List<Product>();
}