存储库/工作单元模式 - 如何在存储库中查询满足特定条件的对象?

时间:2011-05-14 10:43:13

标签: nhibernate entity-framework orm repository-pattern unit-of-work

我在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();

3 个答案:

答案 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>();
    }