如何在不加载内容的情况下在 EntityFramework 中计算行数?

我试图确定如何使用 EntityFramework 对表中的匹配行进行 统计

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

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

我可以加载所有的行和 那么找到伯爵:

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

但这种方法效率极低,有更简单的方法吗?


编辑: 谢谢大家。我已经将数据库从一个私有附件中移除,这样我就可以运行分析; 这有所帮助,但会造成我没有预料到的混乱。

我的实际数据比较深入,我将使用 卡车携带 物品案件托盘——我不希望 卡车离开,除非它至少有一个 物品

我的尝试如下所示。我没有得到的部分是 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 卡车托盘和 Pallet-Case 的关系是多对多-虽然我不认为这有什么关系。我的真实物品是无形的,很难描述,所以我改了名字。]

234933 次浏览

我觉得你想要

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

(编辑以反映评论)

我觉得这样应该行得通。

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();

查询语法:

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 查询。

嗯,即使是 SELECT COUNT(*) FROM Table也会相当低效,特别是在大型表上,因为 SQLServer 除了进行全表扫描(集群索引扫描)之外什么也做不了。

有时,只要知道数据库中大约有多少行就够了,在这种情况下,使用下面这样的语句就足够了:

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

这将检查动态管理视图,并从中提取行数和表大小(给定一个特定的表)。它通过汇总堆(index _ id = 0)或聚集索引(index _ id = 1)的条目来完成。

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

也许这对你也有用?当然,要在 EF 中使用它,您必须将它包装在一个存储过程中,或者使用一个直接的“ Execute SQL query”调用。

马克

使用实体上下文的 < em > 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>();
}

据我所知,所选择的答案仍然加载所有相关的测试。根据这个 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();
}

这是我的暗号:

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

确保变量定义为 IQueryable,然后当您使用 Count ()方法时,EF 将执行类似于

select count(*) from ...

否则,如果将记录定义为 IEnumable,则生成的 sql 将查询整个表并计算返回的行数。