实体框架,通用存储库模式和奇怪的SQL生成

use*_*563 4 sql generics entity-framework repository

我已经实现了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;
    }
}
Run Code Online (Sandbox Code Playgroud)

一种方法是QueryCount(),我想充当选择Count(*)...其中 SQL行(不返回实际记录).

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

AllAppContainer allAppContainer = new AllAppContainer();
int nonRepCount = allAppContainer.Items.Count(item => item.Id > 0);
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

真厉害!得分了!

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

Repository<Item> repository = new Repository<Item>();
int repCount = repository.QueryCount(item => item.Id > 0);
Run Code Online (Sandbox Code Playgroud)

这是生成的SQL:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[SmallField] AS [SmallField]
FROM [dbo].[Items] AS [Extent1]
Run Code Online (Sandbox Code Playgroud)

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

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

int queryCount = new AllAppContainer().CreateObjectSet<T>().Count(predicate);
Run Code Online (Sandbox Code Playgroud)

和非存储库行:

int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);
Run Code Online (Sandbox Code Playgroud)

但每个生成的SQL与以前相同.

现在为什么所有这个存储库 - 返回所有匹配记录然后计数正在发生,而不是非存储库?有没有什么方法可以通过我的通用存储库做我想要的东西,即数据为db.我不能记住内存计数性能.

Kri*_*nov 7

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

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

  • @BlueRaja:你想把什么叫做bug?不完全理解IEnumerable <T>和IQueryable <T>之间的区别不是一个bug.这是正确使用Linq必须具备的关键知识. (2认同)
  • @BlueRaja:我不同意.而且它与EF无关. (2认同)