当前位置: 首页 > 知识库问答 >
问题:

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

葛承嗣
2023-03-14

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

使用实体框架6.1实现数据访问层

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

这个想法是,定义一个通用接口IRepository和一个隐藏数据实际访问方式的类存储库。可以使用实体框架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和/或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);

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

问题:为什么不推荐这样做?人们会以不可取的方式更改数据吗?

共有2个答案

司寇书
2023-03-14

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

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

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

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

你能看出这两段代码的区别吗?唯一的区别在第一行。在第一个例子中,我们使用上下文。订单,在第二个我们使用仓库。GetOrders()。那么,这个存储库在解决什么问题呢?没什么!

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

var orders = repository.GetOrders(1234);

看到区别了吗?检索自Hamedani先生的博客

东门宜
2023-03-14

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

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

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

 类似资料:
  • 问题内容: 我已经为Entity Framework 4实现了通用存储库。这是一个简化版本,其中AllAppContainer是EF4对象上下文: 一种方法是QueryCount(),我想将其用作 select Count(*)… SQL行(不返回实际记录)。 直截了当?您可能会想…首先,让我们做同一件事的非存储库版本,对Item实体进行计数: SQL Server Profiler说生成的SQL

  • 这是我要测试的类 这是测试类 当我做这个测试的时候 我创建这些类时参考了其他已有的代码,来自不同的地方,并且没有真正理解如何进行注释(部分原因是时间不够),所以如果有人能告诉我,不仅是如何修复,而且还有为什么我错了,我会非常感激的! 编辑: 我做了@Nikolas Charalambidis建议的更改(谢谢!),所以我的类现在看起来与 通过稍加搜索,从这个SO答案中,我觉得我不应该@autowir

  • 问题内容: 我试图从存储过程中获取简单的输出 和我的MVC 但是当我编译时,在以下部分出现错误: 方法’sp_getrandomnumber’的重载没有接受1个参数 名称“ randoms”在当前上下文中不存在 提前非常感谢希什 问题答案: 您的问题是您的SPROC输出是一个int。 请参见Scott Gu的文章中的以下引用。 “ LINQ to SQL将SPROC中的“ out”参数映射为参考参

  • 问题内容: 我已经创建了这个并且尝试使用实体框架来调用它。下面是用C#编写的代码。 在所有情况下都返回。请让我知道错误。 编辑 -根据给定的答案,不使用存储过程的return语句,因为Entity Framework不支持开箱即用的存储过程返回标量值。让我知道如何从中发送标量数据? 问题答案: 您的存储过程当前返回 标 量值。使用以下步骤来解决此问题: 像这样更改您的存储过程(不要在存储过程中使用

  • 我在后端代码中使用了Spring数据jpa。我已经包含了实体,dto接口,服务和jpa存储库代码。 现在的问题是,当我在< code>TopicService中调用< code>getAllTopics()时。它返回< code>Topic对象的列表,而不是< code>TopicDto。< code>Topic对象包含一个< code >示例列表,我没有将它包含在< code>TopicDto中