假设我有以下EF6 Linq语句,该语句计算2个表的项目数(Table1有10个项目,而Table2没有项目):
var q = db.Table1.GroupBy(g => "Table1").Select(g => new { Name = g.Key, EntryCount = g.Count() })
.Union(db.Table2.GroupBy(g => "Table2").Select(g => new { Name = g.Key, EntryCount = g.Count() }));
var r = q.ToList();
预期结果应该类似于
Name | EntryCount
---------------------
Table1 | 10
Table2 | 0
但是因为Table2没有任何项目,所以它没有出现在最终结果中,并且得到以下结果:
Name | EntryCount
---------------------
Table1 | 10
我如何确保表2总是出现在最终列表中,即使它为空并且没有任何记录?
[为您提供我为什么要执行此Linq语句的背景,我将以下TSQL语句转换为linq查询:
CREATE FUNCTION [dbo].[ufnGetLookups] ()
RETURNS
@lookupsWithItemCounts TABLE
(
[Name] VARCHAR(100),
[EntryCount] INT
)
AS
BEGIN
INSERT INTO @lookupsWithItemCounts([Name],[EntryCount])
VALUES
('Table1', (SELECT COUNT(*) FROM Table1)),
('Table2', (SELECT COUNT(*) FROM Table2)),
('Table3', (SELECT COUNT(*) FROM Table3))
RETURN;
END
对于使此linq语句在一个数据库行程中运行,而不是多次运行,这也非常重要。
您可以通过创建一个默认表并在其中包含一行来做到这一点。
var ans = Table1.GroupBy(u => "Table1")
.Select(ug => new { Name = ug.Key, EntryCount = ug.Count() })
.Union(Table2.GroupBy(l => "Table2")
.Select(lg => new { Name = lg.Key, EntryCount = lg.Count() })
.Union(OneRowTable.GroupBy(u2 => 1)
.Select(u2g => new { Name = "Table2", EntryCount = u2g.Count()-1 }) )
.OrderByDescending(cg => cg.EntryCount)
.Take(1)
);
这是通过LINQ to SQL和LINQ to EF Core 3.0在单次往返数据库中进行评估的。我无法轻松地使用LINQ to EF进行测试。
[如果您有一个表列表,则表列表可用于将union
与EntryCount = 0
合并为一行,然后在最终结果集上,在名称和GroupBy
的Sum
上设置EntryCount
将提供所需的结果。
//List of tables
var tableList = new string[] { "Table1", "Table2" };
var res = db.Table1
.GroupBy(t1 => "Table1")
.Select(gt1 => new { Name = gt1.Key, EntryCount = gt1.Count()})
.Union(db.Table2
.GroupBy(t2 => "Table2")
.Select(gt2 => new { Name = gt2.Key, EntryCount = gt2.Count()})
)
.Union(tableList
.GroupBy(s => s)
.Select(gs => new { Name = gs.Key, EntryCount = 0 })
)
.GroupBy(gg => gg.Name)
.Select(fg => new {Name = fg.Key, EntryCount=fg.Select(ee => ee.EntryCount).Sum()})
.ToList();
结果将具有列表中所有表的EntryCount。