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

实体框架、通用存储库模式和奇怪的SQL生成,sql,entity-framework,repository,generics,Sql,Entity Framework,Repository,Generics,我已经为EntityFramework4实现了一个通用存储库。下面是一个简化版本,其中AllAppContainer是EF4对象上下文: public class Repository<T> where T : class { protected AllAppContainer objectContext; protected ObjectSet<T> entitySet; public Repository() { ob

我已经为EntityFramework4实现了一个通用存储库。下面是一个简化版本,其中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;
    }
}
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]
呜呜!得分

现在,让我们使用my Repository QueryCount调用相同的函数:

Repository<Item> repository = new Repository<Item>();
int repCount = repository.QueryCount(item => item.Id > 0);
是的,EF返回完整的数据集,然后在内存中对其调用Count()

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

int queryCount = new AllAppContainer().CreateObjectSet<T>().Count(predicate);
int queryCount=new AllAppContainer().CreateObjectSet().Count(谓词);
和非存储库行,以:

int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);
int nonRepCount=allAppContainer1.CreateObjectSet().Count(item=>item.Id>0);
但是为每种类型生成的SQL与以前相同


现在,为什么所有存储库都会返回所有匹配的记录,然后计数会发生,而对于非存储库则不会?还有,是否有任何方法可以通过我的通用存储库(即数据库计数)实现我想要的功能。我无法承受内存中计数性能的影响。

您需要对
计数使用
表达式谓词
,否则框架将使用
Enumerable.count方法(IEnumerable,Func)
,该方法使DB中的整个集合能够调用每个项,因此您的方法应该是:

public int QueryCount(Expression<Func<T, Boolean>> predicate)
{
    int queryCount = entitySet.Count(predicate);
    return queryCount;
}
public int QueryCount(表达式谓词)
{
int queryCount=entitySet.Count(谓词);
返回查询计数;
}

+1另请参见和-我几乎可以称之为bug。哇,我现在不在上班,但我明天会跑过来检查一下。谢谢你的快速回复K。也谢谢你的指南针BlueRaja-令人沮丧的是不知道在这个问题上要搜索的术语:我的和另外两个问题有完全不同的标题/主题,但显然是来自同一个问题。@BlueRaja:你想把一个bug称为什么?不完全理解IEnumerable和IQueryable之间的区别并不是一个bug。这是正确使用Linq必须具备的关键知识。@Ladislav:这与
IQueryable
IEnumerable
之间的差异无关-这是实体框架中的一个错误。我还没有遇到过一个人,他第一眼看到
.Where(MyFunc)
.Where(o=>MyFunc(o))
会有完全不同的行为。当一个API像那样令人难以置信且不必要地违反直觉时,我称之为bug。@BlueRaja:我不同意。此外,它与EF无关。
int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);
public int QueryCount(Expression<Func<T, Boolean>> predicate)
{
    int queryCount = entitySet.Count(predicate);
    return queryCount;
}