什么是在存储库模式中使用IQueryable <t>的替代方法?</t>

时间:2013-05-31 01:29:30

标签: entity-framework repository-pattern iqueryable

我是ASP.NET MVC新手(但是.NET经验丰富的开发者),我正在努力学习如何正确设置Web应用程序基础结构。 存储库模式是我现在正在考虑的,在过去几天阅读了几十篇博客/文章/答案后,我仍然不确定如何以正确的方式使用它。我正在学习Pro ASP.NET MVC 4 Adam Freeman,这里是基于本书的存储库接口代码:

public interface IRepository<T>
{
    IQueryable<T> FindAll();
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);

    void Add(T newEntity);
    void Remove(T entity);

    T FindById(long id);
}

经过更多的在线研究后,我意识到许多人认为从存储库中返回IQueryable是不好的做法,我可以(大部分)理解为什么。但是,我似乎无法找到具体替代方案的答案?我知道有一个自定义存储库的想法,对于每个实体,每个可能的查询都有专门的方法,基本上会返回IEnumerable而不是IQueryable ......但这对我来说似乎不对(它也不是优雅的解决方案)许多代码编写和可能的代码冗余等...)。

还有什么其他选择?

2 个答案:

答案 0 :(得分:7)

你有两种选择。

规格模式

第一个是使用specification pattern。您创建了一组用于限制搜索结果的类。

维基百科的文章有点差,因为它没有显示如何编写业务规范(即“真实”规范)。但是你基本上在业务规范中使用较低级别的规范(和/或等)。

通过这样做,您可以拥有更简单的存储库类,而不是编写这些规范。

特定存储库。

为每个根聚合(订单,用户等)创建存储库。每个存储库都具有适用于特定业务需求的唯一查询方法。

用户存储库可以有例如

IPagedResult<User> FindDisabledUser(int pageNumber, int pageSize);

订单存储库可以有

IPagedResult<User> GetOrdersReadyForShipping(DateTime orderAfterThisDate);

我写了一组数据层文章:http://blog.gauffin.org/tag/data-access/。其中一个也解释了为什么在您的存储库中公开IQueryable<T>不是一个好主意。

答案 1 :(得分:4)

根据我在原始问题下面的评论,这就是我如何实现需要更复杂查询要求的存储库。我还为实体框架包含了我的DbContext对象。

我喜欢这种模式,因为它隐藏了存储库后面的实体框架实现,确保实体框架不与您的应用程序紧密耦合。

public class PersonRepository: IPersonRepository
{
    public List<Person> ReadAll()
    {
        using (var context = new EfContext())
            return context.Persons.ToList();
    }

    public List<Person> ReadPage(int pageIndex, int itemCount)
    {
        using (var context = new EfContext())
            return context.Persons
                          .Skip(pageIndex * itemCount)
                          .Take(itemCount)
                          .ToList();

    }

    public List<Person> ReadAllWhoseNamesStartWith(string nameExpression)
    {
        using (var context = new EfContext())
            return context.Persons
                          .Where(r => r.Name.StartsWith(nameExpression)
                          .ToList();
    }

    public List<Person> ReadAllWhoseFavouriteColorIs(string color)
    {
        using (var context = new EfContext())
            return context.Persons
                          .Where(r => r.FavoriteColor.StartsWith(color)
                          .ToList();
    }
}

public class EfContext: DbContext
{
    public EfContext(): base("DefaultConnection")
    {
    }

    public DbSet<Person> Persons { get; set; }
    public DbSet<Car> Cars { get; set; }
    public DbSet<Car> Houses { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<EfContext>(null);
        base.OnModelCreating(modelBuilder);
    }
}