вернуть 0 для количества элементов в операторе linq - PullRequest
1 голос
/ 12 февраля 2020

Допустим, у меня есть следующий оператор 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, я преобразовываю следующий оператор T SQL в запрос 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 выполнялся в одной поездке базы данных, а не в нескольких.

Ответы [ 2 ]

2 голосов
/ 13 февраля 2020

Если у вас есть список таблиц, тогда список таблиц можно использовать для 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 для всех таблиц в списке.

2 голосов
/ 12 февраля 2020

Вы можете сделать это, создав таблицу по умолчанию с одной строкой в ​​ней.

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 to EF.

Обратите внимание, что в EF Core 3.0 исходный запрос транслируется таким образом, чтобы возвращать строку 0 для любых пустых таблиц.

...