C# 为linq语句中的项目计数返回0

C# 为linq语句中的项目计数返回0,c#,entity-framework,linq,linq-to-sql,linq-to-entities,C#,Entity Framework,Linq,Linq To Sql,Linq To Entities,假设我有以下EF6 Linq语句,它统计两个表的项目数(表1有10个项目,表2没有项目): 预期的结果应该是 Name | EntryCount --------------------- Table1 | 10 Table2 | 0 但是,由于表2没有任何项目,因此它不会出现在最终结果中,我得到以下结果: Name | EntryCount --------------------- Table1 | 10 如何确保表2始终出现在最终列表中,即使它是空的并且

假设我有以下EF6 Linq语句,它统计两个表的项目数(表1有10个项目,表2没有项目):

预期的结果应该是

Name    | EntryCount
---------------------
Table1  |   10
Table2  |    0
但是,由于表2没有任何项目,因此它不会出现在最终结果中,我得到以下结果:

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到SQL在数据库的一次往返过程中进行评估的。我不能轻易地用LINQ测试EF


请注意,在EF Core 3.0中,原始查询的转换方式是为任何空表返回
0
行。

您可以通过创建一个包含单行的默认表来实现这一点

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到SQL在数据库的一次往返过程中进行评估的。我不能轻易地用LINQ测试EF


请注意,在EF Core 3.0中,原始查询的转换方式是为任何空表返回一个
0
行。

如果您有一个表列表,那么可以使用表列表来
联合
一个
EntryCount=0
的行,然后在最终结果集上设置
GroupBy
EntryCount
的名称和
Sum
期望的结果

//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

如果您有一个表列表,那么可以使用表列表来
合并
具有
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

为什么不做简单的计数呢?i、 e.
db.Table1.Count()
db.Table2.Count()
,是否担心以后的捆绑?这似乎更有可能给你想要的结果;事实上,任何超过零行的分组都是零组,即使分组是“所有行”分组,为什么要使用union?看起来您可以这样做:
var r=new[]{new{Name=“Table1”,EntryCount=db.Table1.Count()},new{Name=“Table2”,EntryCount=db.Table2.Count()}我正试图找到与我粘贴的TSQL语句等效的linq。@MarcGravell,我希望linq查询一次从数据库获取结果,并替换我粘贴的TSQL函数。如果在一个linq查询中不可能做到这一点,那么我将使用本机sql函数。如果在表2的
选择
之前添加
DefaultIfEmpty()
会怎么样?为什么不进行简单的计数呢?i、 e.
db.Table1.Count()
db.Table2.Count()
,是否担心以后的捆绑?这似乎更有可能给你想要的结果;事实上,任何超过零行的分组都是零组,即使分组是“所有行”分组,为什么要使用union?看起来您可以这样做:
var r=new[]{new{Name=“Table1”,EntryCount=db.Table1.Count()},new{Name=“Table2”,EntryCount=db.Table2.Count()}我正试图找到与我粘贴的TSQL语句等效的linq。@MarcGravell,我希望linq查询一次从数据库获取结果,并替换我粘贴的TSQL函数。如果在一个linq查询中不可能实现这一点,那么我将使用本机sql函数。如果在表2的
选择
之前添加
DefaultIfEmpty()
会怎么样?当我尝试此函数的变体时,LINQ-to-SQL转换器拒绝了
EntryCount=0
。在那里放置
AsEnumerable
似乎效果不错,尤其是在EF 3.0中,它生成了一个非常简单的SQL查询。有趣的是,原始的简单查询在EF 3.0中生成了一个
0
count记录,因此不需要对其进行处理。使用
Table2
查询零行:
var-ans=Table1.GroupBy(t1=>“Table1”)。选择(gt1=>new{Name=gt1.Key,EntryCount=gt1.count())。联合(Table2.GroupBy(t2=>“Table2”).Select(gt2=>new{Name=gt2.Key,EntryCount=gt2.Count()}))
;针对MS SQL Server运行。结果SQL:
选择N'Users'作为[Name],从[user]作为[u]UNION选择N'TblLogs'作为[Name],从[tblLog]作为[EntryCount]作为[t]GO
。我在我的答案中添加了注释。当我尝试这种变化时,LINQ-to-SQL转换器拒绝了
EntryCount=0
。在那里放置
AsEnumerable
似乎效果不错,尤其是在EF 3.0中,它生成了一个非常简单的SQL查询。有趣的是,原始的简单查询在EF 3.0中生成了一个
0
count记录,因此不需要对其进行处理。使用
Table2
查询零行:
var-ans=Table1.GroupBy(t1=>“Table1”)。选择(gt1=>new{Name=gt1.Key,EntryCount=gt1.count())。联合(Table2.GroupBy(t2=>“Table2”).Select(gt2=>new{Name=gt2.Key,EntryCount=gt2.Count()}))
;针对MS SQL Server运行。结果SQL:
选择N'Users'作为[Name],从[user]作为[u]UNION选择N'TblLogs'作为[Name],从[tblLog]作为[EntryCount]作为[t]GO
。我在回答中添加了注释。