Entity Framework 存储库模式为什么不能 return Iqueryable?
Entity Framework Repository Pattern why not return Iqueryable?
关于如何使用通用 classes 实现存储库模式和工作单元模式,有几篇不错的博客。
Implementing a Data Access Layer with Entity Framework 6.1
Implementing the Repository and Unit of Work Patterns
想法是,定义一个通用接口 IRepository 和一个隐藏数据实际访问方式的 class 存储库。可以使用 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.
}
我经常看到添加了几个类似于 Queryable and/or Enumerable 函数的 Query 函数。
例如在Implementing a data access layer中我看到:
/// 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);
如果接口有函数 IQueryable GetQuery(),那么我就不必创建像 GetFirst() 和 GetByQuery() 这样的函数。
Question: Why is this not recommended? Can people change the data in an undesirable way?
不推荐这样做,因为它会使存储库模式无效。
此模式的目的是通过抽象将您的 DAL 实现与其他项目分开。
本质上 returning IQueryable 会 return TSQL 语句而不是结果,这意味着任何引用您的 DAL 的项目都需要额外引用 EF 才能执行询问。这 'data leak' 会使您的项目更加紧密,从而与关注点分离原则相矛盾。
您可以在此处阅读有关存储库模式及其优点的更多信息:
http://www.codeproject.com/Articles/526874/Repositorypluspattern-cplusdoneplusright
我们使用存储库模式的原因之一是封装胖查询。这些查询使得阅读、理解和测试 ASP.NET MVC 控制器中的操作变得困难。此外,随着应用程序的增长,您在多个地方重复胖查询的机会也会增加。使用存储库模式,我们将这些查询封装在存储库 类 中。结果是更苗条、更清洁、更易于维护和更易于测试的操作。考虑这个例子:
var orders = context.Orders
.Include(o => o.Details)
.ThenInclude(d => d.Product)
.Where(o => o.CustomerId == 1234);
这里我们直接使用没有存储库模式的 DbContext。当您的存储库方法 return IQueryable 时,其他人将获取该 IQueryable 并在其之上编写查询。结果如下:
var orders = repository.GetOrders()
.Include(o => o.Details)
.ThenInclude(d => d.Product)
.Where(o => o.CustomerId == 1234);
你能看出这两个代码片段之间的区别吗?唯一的区别是在第一行。在第一个示例中,我们使用 context.Orders,在第二个示例中我们使用 repository.GetOrders()。那么,这个存储库解决了什么问题?没有!
您的存储库应该 return 域对象。因此,GetOrders() 方法应该 return 一个 IEnumerable。有了这个,第二个例子可以重写为:
var orders = repository.GetOrders(1234);
看出区别了吗?
取自 Hamedani 先生 blog
关于如何使用通用 classes 实现存储库模式和工作单元模式,有几篇不错的博客。
Implementing a Data Access Layer with Entity Framework 6.1
Implementing the Repository and Unit of Work Patterns
想法是,定义一个通用接口 IRepository 和一个隐藏数据实际访问方式的 class 存储库。可以使用 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.
}
我经常看到添加了几个类似于 Queryable and/or Enumerable 函数的 Query 函数。
例如在Implementing a data access layer中我看到:
/// 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);
如果接口有函数 IQueryable GetQuery(),那么我就不必创建像 GetFirst() 和 GetByQuery() 这样的函数。
Question: Why is this not recommended? Can people change the data in an undesirable way?
不推荐这样做,因为它会使存储库模式无效。 此模式的目的是通过抽象将您的 DAL 实现与其他项目分开。
本质上 returning IQueryable 会 return TSQL 语句而不是结果,这意味着任何引用您的 DAL 的项目都需要额外引用 EF 才能执行询问。这 'data leak' 会使您的项目更加紧密,从而与关注点分离原则相矛盾。
您可以在此处阅读有关存储库模式及其优点的更多信息: http://www.codeproject.com/Articles/526874/Repositorypluspattern-cplusdoneplusright
我们使用存储库模式的原因之一是封装胖查询。这些查询使得阅读、理解和测试 ASP.NET MVC 控制器中的操作变得困难。此外,随着应用程序的增长,您在多个地方重复胖查询的机会也会增加。使用存储库模式,我们将这些查询封装在存储库 类 中。结果是更苗条、更清洁、更易于维护和更易于测试的操作。考虑这个例子:
var orders = context.Orders
.Include(o => o.Details)
.ThenInclude(d => d.Product)
.Where(o => o.CustomerId == 1234);
这里我们直接使用没有存储库模式的 DbContext。当您的存储库方法 return IQueryable 时,其他人将获取该 IQueryable 并在其之上编写查询。结果如下:
var orders = repository.GetOrders()
.Include(o => o.Details)
.ThenInclude(d => d.Product)
.Where(o => o.CustomerId == 1234);
你能看出这两个代码片段之间的区别吗?唯一的区别是在第一行。在第一个示例中,我们使用 context.Orders,在第二个示例中我们使用 repository.GetOrders()。那么,这个存储库解决了什么问题?没有!
您的存储库应该 return 域对象。因此,GetOrders() 方法应该 return 一个 IEnumerable。有了这个,第二个例子可以重写为:
var orders = repository.GetOrders(1234);
看出区别了吗? 取自 Hamedani 先生 blog