我已经为 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(),我想将其用作 select Count(*) 。 .. SQL 行(不返回实际记录)。
直截了当?您可能会想...首先,让我们执行相同操作的非存储库版本,对项目实体执行计数:
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]
Woo-hoo!分数!
现在,让我们使用我的存储库 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.count 处进行计数)来做我想做的事情。我无法承受内存计数性能的下降。
I've implemented a generic repository for Entity Framework 4. Here's a dumbed down version, where AllAppContainer is the EF4 object context:
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;
}
}
The one method is QueryCount(), which I want to act as a select Count(*) ... where line of SQL (not returning the actual records).
Straight-forward? You'd think... First, let's do a non-Repository version of the same thing, performing a count on Item entities:
AllAppContainer allAppContainer = new AllAppContainer();
int nonRepCount = allAppContainer.Items.Count(item => item.Id > 0);
SQL Server Profiler says the generated SQL is:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Items] AS [Extent1]
WHERE [Extent1].[Id] > 0
) AS [GroupBy1]
Woo-hoo! Score!
Now let's call the same using my Repository QueryCount:
Repository<Item> repository = new Repository<Item>();
int repCount = repository.QueryCount(item => item.Id > 0);
Here's the generated SQL:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[SmallField] AS [SmallField]
FROM [dbo].[Items] AS [Extent1]
Yep, EF is returning the full set of data, then calling Count() on it in-memory.
For fun I tried changing the relevant line in Repository QueryCount to:
int queryCount = new AllAppContainer().CreateObjectSet<T>().Count(predicate);
and the non-repository line to:
int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);
but the generated SQL for each is the same as before.
Now why would all this repository-returns-all-matching-records-then-counts be happening, when it doesn't for non-repository? And is there any way to do what I want via my generic repository i.e. count at db. I can't take the in-memory count performance hit.
发布评论
评论(1)
您需要使用
Expression>;
,否则框架将使用Count
的谓词Enumerable.Count方法 (IEnumerable, Func)
从数据库获取整个集合以便能够调用每个项目,因此您的方法应该是:you need to use
Expression<Func<TSource, bool>> predicate
for yourCount
otherwise the framework uses theEnumerable.Count<TSource> Method (IEnumerable<TSource>, Func<TSource, Boolean>)
which gets the whole collection from DB to be able to call for each item, so your method should be: