【问题标题】:Entity Framework, Generic Repository Pattern and strange SQL generation实体框架、通用存储库模式和奇怪的 SQL 生成
【发布时间】:2011-02-15 17:45:17
【问题描述】:

我已经为 Entity Framework 4 实现了一个通用存储库。这是一个简化版本,其中 AllAppContainer 是 EF4 对象上下文:

public class Repository<T> where T : class
{
    protected AllAppContainer objectContext;
    protected ObjectSet<T> entitySet;

    public Repository()
    {
        objectContext  = new AllAppContainer();
        entitySet = objectContext.CreateObjectSet<T>();
    }

    public int QueryCount(Func<T, bool> predicate)
    {
        int queryCount = entitySet.Count(predicate);
        return queryCount;
    }
}

一种方法是 QueryCount(),我想将它作为 SQL 的 select Count(*) ... where 行(不返回实际记录)。

直截了当?你会想……首先,让我们做一个非存储库版本的同一件事,对 Item 实体进行计数:

AllAppContainer allAppContainer = new AllAppContainer();
int nonRepCount = allAppContainer.Items.Count(item => item.Id > 0);

SQL Server Profiler 说生成的 SQL 是:

SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Items] AS [Extent1]
    WHERE [Extent1].[Id] > 0
)  AS [GroupBy1]

哇哦!得分!

现在让我们使用我的 Repository QueryCount 调用它:

Repository<Item> repository = new Repository<Item>();
int repCount = repository.QueryCount(item => item.Id > 0);

这是生成的 SQL:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[SmallField] AS [SmallField]
FROM [dbo].[Items] AS [Extent1]

是的,EF 正在返回完整的数据集,然后在内存中对其调用 Count()

为了好玩,我尝试将 Repository QueryCount 中的相关行更改为:

int queryCount = new AllAppContainer().CreateObjectSet<T>().Count(predicate);

和非存储库行:

int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);

但是每个生成的 SQL 都和以前一样。

现在为什么所有这些存储库返回所有匹配记录然后计数都会发生,而不是非存储库?有什么方法可以通过我的通用存储库来做我想做的事,即在 db.我无法承受内存中计数的性能损失。

【问题讨论】:

    标签: sql entity-framework repository generics


    【解决方案1】:

    您需要为您的Count 使用Expression&lt;Func&lt;TSource, bool&gt;&gt; predicate,否则框架使用Enumerable.Count&lt;TSource&gt; Method (IEnumerable&lt;TSource&gt;, Func&lt;TSource, Boolean&gt;) 从数据库中获取整个集合以便能够调用每个项目,因此您的方法应该是:

    public int QueryCount(Expression<Func<T, Boolean>> predicate)
    {
        int queryCount = entitySet.Count(predicate);
        return queryCount;
    }
    

    【讨论】:

    • +1 另见stackoverflow.com/questions/4855399stackoverflow.com/questions/2675536 - 我几乎可以称其为错误。
    • 哇,我现在不在工作,但我明天会去看看这个。感谢 K 的快速响应。感谢 BlueRaja 的指点 - 令人沮丧的是不知道要在这个问题上搜索的术语:我的问题和其他两个问题的标题/主题完全不同,但显然源于同一件事。
    • @BlueRaja:你想把什么叫做错误?不完全理解 IEnumerable 和 IQueryable 之间的区别不是错误。这是正确使用 Linq 必须具备的关键知识。
    • @Ladislav:这与IQueryable&lt;T&gt;IEnumerable&lt;T&gt; 之间的区别无关——这是实体框架中的一个错误。我还没有遇到一个人乍一看会期望.Where(MyFunc).Where(o =&gt; MyFunc(o)) 有如此完全不同的行为。当一个 API 像这样令人难以置信且不必要地违反直觉时,我称之为错误。
    • @BlueRaja:我不同意。而且它与EF无关。
    猜你喜欢
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多