实体框架存储库模式为什么不返回Iqueryable? [英] Entity Framework Repository Pattern why not return Iqueryable?

查看:99
本文介绍了实体框架存储库模式为什么不返回Iqueryable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有几个好的博客关于如何使用通用类实现存储库模式和工作单元模式。

There are several good blogs about how to implement the repository pattern together with the unit-of-work pattern using generic classes.

实体数据访问层与实体框架6.1

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

想法是定义一个通用接口IRepository和一个隐藏数据实际访问的类Repository。可以使用Entity Framework DbContext访问它,也可能是存储库是用于单元测试的内存集合。

The Idea is, to define a generic interface IRepository and a class Repository that hides how the data is actually accessed. It can be accessed using Entity Framework DbContext, or maybe the repository is an in memory collection for unit testing.

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和/或Enumerable函数相似的查询函数。

Quite often I see that several Query functions are added that are similar to Queryable and/or Enumerable functions.

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

/// 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()。

If the interface had a function IQueryable GetQuery(), then I wouldn't have to make functions like GetFirst() and GetByQuery().


问题:为什么不推荐?人们可以以不理想的方式更改数据吗?

Question: Why is this not recommended? Can people change the data in an undesirable way?


推荐答案

存储库模式是封装胖查询。这些查询使ASP.NET MVC控制器中的读取,理解和测试操作变得困难。此外,随着应用程序的增长,您在多个场合重复胖查询的可能性也会增加。使用存储库模式,我们将这些查询封装在存储库类中。结果是更苗条,更干净,更易维护,更易于测试。考虑这个例子:

One of the reasons we use the repository pattern is to encapsulate fat queries. These queries make it hard to read, understand and test actions in ASP.NET MVC controllers. Also, as your application grows, the chances of you repeating a fat query in multiple places increases. With the repository pattern, we encapsulate these queries inside repository classes. The result is slimmer, cleaner, more maintainable and easier-to-test actions. Consider this example:

var orders = context.Orders
    .Include(o => o.Details)
        .ThenInclude(d => d.Product)
    .Where(o => o.CustomerId == 1234);

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

Here we are directly using a DbContext without the repository pattern. When your repository methods return IQueryable, someone else is going to get that IQueryable and compose a query on top of it. Here’s the result:

var orders = repository.GetOrders()
    .Include(o => o.Details)
        .ThenInclude(d => d.Product)
    .Where(o => o.CustomerId == 1234);

您可以看到这两个代码段之间的区别吗?唯一的区别是第一行。在第一个例子中,我们使用context.Orders,第二个我们使用repository.GetOrders()。那么这个仓库解决了什么问题呢?没有!

Can you see the difference between these two code snippets? The only difference is in the first line. In the first example, we use context.Orders, in the second we use repository.GetOrders(). So, what problem is this repository solving? Nothing!

您的存储库应返回域对象。所以,GetOrders()方法应该返回一个IEnumerable。这样,第二个例子可以重写为:

Your repositories should return domain objects. So, the GetOrders() method should return an IEnumerable. With this, the second example can be re-written as:

var orders = repository.GetOrders(1234);

看到差异?

这篇关于实体框架存储库模式为什么不返回Iqueryable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆