Получение количества ЛЕВОЙ СОЕДИНЕННОЙ сущности через группу по - PullRequest
0 голосов
/ 28 февраля 2019

Рассмотрим следующий запрос, который должен возвращать режиссера вместе с количеством фильмов и актеров для каждого фильма.Как написать это в LINQ, используя EF CORE 2.2?Мне нужен LINQ для генерации SQL, который фактически использует GROUP BY с агрегатами SQL, как это поддерживается в EF CORE 2.1 и более поздних версиях.

SELECT DirectorName, COUNT(m.MovieID), COUNT(a.ActorID)
FROM Directors d
LEFT OUTER JOIN Movies AS m ON m.DirectorID = d.DirectorID
LEFT OUTER JOIN Actors AS a ON a.MovieID = m.MovieID
WHERE d.DirectorID = 1
GROUP BY DirectorName

Пример запроса LINQ был построен на основе ответа и дает мне результаты, но в запросе есть только одно ЛЕВНОЕ соединение и нет группировки по.Вывод указывает, что DefaultIfEmpty (), GroupBy и Count не могут быть переведены и будут оцениваться локально.

var results =
(
    from d in _moviesContext.Directors
    join m in _moviesContext.Movies on d.DirectorId equals m.DirectorId 
        into grpM from movies in grpM.DefaultIfEmpty()
    join a in _moviesContext.Actors on movies.MovieId equals a.MovieId
        into grpA from actors in grpA.DefaultIfEmpty()
    where d.DirectorId == 1
    group new { d, grpM, grpA } by new
    {
        d.DirectorName
    } into grp
    select new
    {
        DirectoryName = grp.Key.DirectorName,
        MovieCount = grp.Sum(g => g.grpM.Count()),
        ActorAcount = grp.Sum(g => g.grpA.Count())
    }
).ToList();

Выражение LINQ 'DefaultIfEmpty ()' не может быть переведено и будет оцениваться локально,Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ «DefaultIfEmpty ()» не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ 'из фильмов фильмов в {[grpM] => DefaultIfEmpty ()}' не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ 'GroupBy (new <> f__AnonymousType8 1(DirectorName = [d].DirectorName), new <>f__AnonymousType6 2 (d = [d], grpM = [grpM]))' не может быть переведено и будет оценено локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ «DefaultIfEmpty ()» не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ «DefaultIfEmpty ()» не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ 'из фильмов фильмов в {[grpM] => DefaultIfEmpty ()}' не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение. Выражение LINQ 'GroupBy (new <> f__AnonymousType8 1(DirectorName = [d].DirectorName), new <>f__AnonymousType6 2 (d = [d], grpM = [grpM]))' не может быть переведено и будет оценено локально.Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ 'Count ()' не может быть переведено и будет оцениваться локально.Microsoft.EntityFrameworkCore.Query: Предупреждение: выражение LINQ 'Sum ()' не может быть переведено и будет оценено локально.

Вот модели

public partial class Directors
{
    public int DirectorId { get; set; }
    public string DirectorName { get; set; }
}

public partial class Movies
{
    public int MovieId { get; set; }
    public string MovieName { get; set; }
    public int? DirectorId { get; set; }
}

public partial class Actors
{
    public int ActorId { get; set; }
    public string ActorName { get; set; }
    public int? MovieId { get; set; }
}

1 Ответ

0 голосов
/ 28 февраля 2019

Я не уверен, почему ваши актеры имеют только int для идентификатора фильма, когда у актера обычно есть список фильмов, но я считаю, что вам нужно включить в группу все три типа объектов, а затем выбрать отдельные фильмы и отдельных актеров, чтобыполучить счет.

Пример:

var directors = new[] { new { DirectorName = "Director A", DirectorID = 1 },
                        new { DirectorName = "Director B", DirectorID = 2 }};
var movies = new[] { new { MovieName = "Movie A", MovieID = 1, DirectorID = 1 },
                     new { MovieName = "Movie B", MovieID = 2, DirectorID = 2 }};
var actors = new[] { new { ActorName = "Actor A", ActorID = 1, MovieID = 1},
                     new { ActorName = "Actor B", ActorID = 2, MovieID = 1},
                     new { ActorName = "Actor C", ActorID = 3, MovieID = 1},
                     new { ActorName = "Actor D", ActorID = 4, MovieID = 2}};

var results = from d in directors
              from m in movies
                .Where(m => m.DirectorID == d.DirectorID)
              from a in actors
                .Where(a => a.MovieID == m.MovieID)
              where d.DirectorID == 1
              group new { d, m, a } by d.DirectorName into grp
              select new 
              { DirectorName = grp.Key,
                MovieCount = grp.Select(x => x.m).Distinct().Count(),
                ActorCount = grp.Select(x => x.a).Distinct().Count()
              };

Даст

result = new [] { new { DirectorName = "Director A", MovieCount = 1, ActorCount = 3}};
...