实体框架存储库模式为什么不返回Iqueryable?

Har*_*lse 8 entity-framework repository-pattern

有几个很好的博客关于如何使用泛型类实现存储库模式以及工作单元模式.

使用Entity Framework 6.1实现数据访问层

实施存储库和工作单元模式

想法是定义一个通用接口IRepository和一个隐藏数据实际访问方式的类存储库.可以使用Entity Framework DbContext访问它,也可以使用存储库作为内存集合进行单元测试.

public interface public interface IRepository<T> where T : class
{
    T GetById(int Id);
    void DeleteById(int Id);

    void Add(T entity);
    void Update(T entity);

    etc.
}
Run Code Online (Sandbox Code Playgroud)

我经常看到添加了几个类似于Queryable和/或Enumerable函数的Query函数.

例如,在实现数据访问层中,我看到:

/// Returns an IEnumerable based on the query, order clause and the properties included
/// <param name="query">Link query for filtering.</param>
/// <param name="orderBy">Link query for sorting.</param>
/// <param name="includeProperties">Navigation properties seperated by comma for eager loading.</param>
/// <returns>IEnumerable containing the resulting entity set.</returns>
IEnumerable<T> GetByQuery(Expression<Func<T, bool>> query = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");

/// <summary>
/// Returns the first matching entity based on the query.
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
T GetFirst(Expression<Func<T, bool>> predicate);
Run Code Online (Sandbox Code Playgroud)

如果接口有一个函数IQueryable GetQuery(),那么我就不必创建像GetFirst()和GetByQuery()这样的函数.

问题:为什么不推荐这个?人们可以以不合需要的方式更改数据吗?

小智 9

不建议这样做,因为它会使存储库模式无效。此模式的目的是通过抽象的方式将 DAL 实现与其他项目分开。

本质上,返回 IQueryable 将返回 TSQL 语句,而不是结果,这意味着引用 DAL 的任何项目都需要对 EF 进行额外引用才能执行查询。这种“数据泄漏”将使您的项目更加紧密,从而与关注点分离原则相矛盾。

您可以在此处阅读有关存储库模式及其优点的更多信息: http://www.codeproject.com/Articles/526874/Repositorypluspattern-cplusdoneplusright


Ali*_*yat 5

我们使用存储库模式的原因之一是封装胖查询.这些查询使得在ASP.NET MVC控制器中难以阅读,理解和测试操作.此外,随着应用程序的增长,您在多个位置重复胖查询的可能性也会增加.使用存储库模式,我们将这些查询封装在存储库类中.结果是更轻薄,更清洁,更易于维护且更易于测试.考虑这个例子:

var orders = context.Orders
    .Include(o => o.Details)
        .ThenInclude(d => d.Product)
    .Where(o => o.CustomerId == 1234);
Run Code Online (Sandbox Code Playgroud)

这里我们直接使用没有存储库模式的DbContext.当您的存储库方法返回IQueryable时,其他人将获得IQueryable并在其上编写查询.这是结果:

var orders = repository.GetOrders()
    .Include(o => o.Details)
        .ThenInclude(d => d.Product)
    .Where(o => o.CustomerId == 1234);
Run Code Online (Sandbox Code Playgroud)

你能看出这两个代码片段之间的区别吗?唯一的区别在于第一行.在第一个例子中,我们使用context.Orders,在第二个例子中我们使用repository.GetOrders().那么,这个存储库解决了什么问题?没有!

您的存储库应该返回域对象.因此,GetOrders()方法应返回IEnumerable.有了这个,第二个例子可以重写为:

var orders = repository.GetOrders(1234);
Run Code Online (Sandbox Code Playgroud)

看到不同?取自Hamedani先生的博客

  • 嘿,它是来自这个博客的文本的复制粘贴:https://programmingwithmosh.com/entity-framework/common-mistakes-with-the-repository-pattern/.你应该提到信息"借来" - ))) (8认同)
  • 我认为您错过了第一个版本和第二个版本的一个重要方面。第一个要求消费者“知道”上下文是什么。这意味着它取决于例如 EF6。第二个只需要知道 IEnumerable 是什么。 (3认同)