如何在没有加载内容的情况下在EntityFramework中COUNT行?

我试图确定如何使用EntityFramework来统计表上的匹配行。

问题是每行可能有很多兆字节的数据(在二进制字段中)。 当然,SQL会是这样的:

SELECT COUNT(*) FROM [MyTable] WHERE [fkID] = '1'; 

我可以加载所有的行, 然后find计数:

 var owner = context.MyContainer.Where(t => t.ID == '1'); owner.MyTable.Load(); var count = owner.MyTable.Count(); 

但是这是非常低效的。 有一个更简单的方法吗?


编辑:谢谢,所有。 我已经从一个私人连接移动数据库,所以我可以运行分析; 这有助于但却导致我没有想到的混乱。

而且我的真实数据会更深一些,我会用卡车运载物品的 货盘 – 而且我不想卡车离开,除非至less有一个物品在里面。

我的尝试如下所示。 我没有得到的部分是CASE_2不能访问数据库服务器(MSSQL)。

 var truck = context.Truck.FirstOrDefault(t => (t.ID == truckID)); if (truck == null) return "Invalid Truck ID: " + truckID; var dlist = from t in ve.Truck where t.ID == truckID select t.Driver; if (dlist.Count() == 0) return "No Driver for this Truck"; var plist = from t in ve.Truck where t.ID == truckID from r in t.Pallet select r; if (plist.Count() == 0) return "No Pallets are in this Truck"; #if CASE_1 /// This works fine (using 'plist'): var list1 = from r in plist from c in r.Case from i in c.Item select i; if (list1.Count() == 0) return "No Items are in the Truck"; #endif #if CASE_2 /// This never executes any SQL on the server. var list2 = from r in truck.Pallet from c in r.Case from i in c.Item select i; bool ok = (list.Count() > 0); if (!ok) return "No Items are in the Truck"; #endif #if CASE_3 /// Forced loading also works, as stated in the OP... bool ok = false; foreach (var pallet in truck.Pallet) { pallet.Case.Load(); foreach (var kase in pallet.Case) { kase.Item.Load(); var item = kase.Item.FirstOrDefault(); if (item != null) { ok = true; break; } } if (ok) break; } if (!ok) return "No Items are in the Truck"; #endif 

而CASE_1产生的SQL通过sp_executesql传递,但是:

 SELECT [Project1].[C1] AS [C1] FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1] LEFT OUTER JOIN (SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(cast(1 as bit)) AS [A1] FROM [dbo].[PalletTruckMap] AS [Extent1] INNER JOIN [dbo].[PalletCaseMap] AS [Extent2] ON [Extent1].[PalletID] = [Extent2].[PalletID] INNER JOIN [dbo].[Item] AS [Extent3] ON [Extent2].[CaseID] = [Extent3].[CaseID] WHERE [Extent1].[TruckID] = '....' ) AS [GroupBy1] ) AS [Project1] ON 1 = 1 

[ 我真的没有卡车,司机,货盘,案件或物品; 正如你可以从SQL中看到的,货车 – 托盘和托盘 – 箱子之间的关系是多对多的 – 尽pipe我不这么认为。 我的真实对象是无形的,难以描述,所以我改了名字。 ]

查询语法:

 var count = (from o in context.MyContainer where o.ID == '1' from t in o.MyTable select t).Count(); 

方法语法:

 var count = context.MyContainer .Where(o => o.ID == '1') .SelectMany(o => o.MyTable) .Count() 

两者都生成相同的SQL查询。

我想你想要类似的东西

 var count = context.MyTable.Count(t => t.MyContainer.ID == '1'); 

(编辑以反映评论)

据我所知,所选的答案仍然加载所有相关的testing。 根据这个msdn博客,有一个更好的方法。

http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx

特别

 using (var context = new UnicornsContext()) var princess = context.Princesses.Find(1); // Count how many unicorns the princess owns var unicornHaul = context.Entry(princess) .Collection(p => p.Unicorns) .Query() .Count(); } 

那么,即使是SELECT COUNT(*) FROM Table也是非常低效的,特别是在大型表上,因为SQL Server实际上不能做任何事情,除了做一个全表扫描(聚簇索引扫描)。

有时,从数据库中知道大概的行数就足够了,在这种情况下,像这样的语句就足够了:

 SELECT SUM(used_page_count) * 8 AS SizeKB, SUM(row_count) AS [RowCount], OBJECT_NAME(OBJECT_ID) AS TableName FROM sys.dm_db_partition_stats WHERE OBJECT_ID = OBJECT_ID('YourTableNameHere') AND (index_id = 0 OR index_id = 1) GROUP BY OBJECT_ID 

这将检查dynamicpipe理视图,并从中提取行数和表大小,给定一个特定的表。 它通过总结堆(index_id = 0)或聚簇索引(index_id = 1)的条目来实现。

它很快,很容易使用,但不能保证100%准确或最新。 但在很多情况下,这是“足够好”(并且减轻了服务器的负担)。

也许这也适用于你? 当然,要在EF中使用它,你必须把它包装在一个存储过程中,或者使用一个直接的“执行SQL查询”调用。

渣子

这是我的代码:

 IQueryable<AuctionRecord> records = db.AuctionRecord; var count = records.Count(); 

确保将variables定义为IQueryable,然后在使用Count()方法时,EF将执行类似的操作

 select count(*) from ... 

否则,如果logging被定义为IEnumerable,则生成的SQL将查询整个表并计算返回的行数。

使用实体上下文的ExecuteStoreQuery方法。 这避免了下载整个结果集和反序列化对象来做一个简单的行计数。

  int count; using (var db = new MyDatabase()){ string sql = "SELECT COUNT(*) FROM MyTable where FkId = {0}"; object[] myParams = {1}; var cntQuery = db.ExecuteStoreQuery<int>(sql, myParams); count = cntQuery.First<int>(); } 

我认为这应该工作…

 var query = from m in context.MyTable where m.MyContainerId == '1' // or what ever the foreign key name is... select m; var count = query.Count();