Конвертировать SQL в Linq с EF Core - PullRequest
0 голосов
/ 20 января 2019

Я использую .NET Core 2.2, EF Core, C # и SQL Server 2017. Я не могу перевести нужный мне запрос в Linq.

Это запрос, который мне нужно преобразовать:

SELECT      TOP 5
            p.Id, 
            p.Title, 
            AVG(q.RatingValue) AvgRating
FROM        Movies AS p
INNER JOIN  Ratings AS q ON p.Id = q.MovieId
GROUP BY    p.Id, p.Title
ORDER BY    AvgRating DESC, p.Title ASC

Идея предыдущего запроса состоит в том, чтобы получить Топ-5 фильмов в соответствии со средним рейтингом, упорядочив их сначала по наибольшему среднему значению, а в случае того же среднего порядка по алфавиту.

ИтакПока это мой запрос, который делает соединение, но затем все еще отсутствует: группировка по, среднему и порядку:

public class MovieRepository : IMovieRepository
{
    private readonly MovieDbContext _moviesDbContext;
    public MovieRepository(MovieDbContext moviesDbContext)
    {
        _moviesDbContext = moviesDbContext;
    }

    public IEnumerable<Movie> GetTopFive()
    {
        var result = _moviesDbContext.Movies.OrderByDescending(x => x.Id).Take(5).
                     Include(x => x.Ratings);

        return result;
    }
}

А это сущности:

 public class Movie
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int YearOfRelease { get; set; }
    public string Genre { get; set; }
    public int RunningTime { get; set; }
    public IList<Rating> Ratings { get; set; }
}

public class Rating
{
    public int Id { get; set; }
    public int MovieId { get; set; }
    public int UserId { get; set; }
    public decimal RatingValue { get; set; }
}

Я пыталсяиспользовать инструмент Linqer также для преобразования моего запроса в Linq, но он не работал.

Буду признателен за любую помощь в преобразовании этого запроса в LINQ для метода "GetTopFive".

Спасибо

Ответы [ 3 ]

0 голосов
/ 20 января 2019

Попробуйте это -

var data = _moviesDbContext.Movies.Include(x => x.Ratings)
            .Select(x => new {
                Id = x.Id,
                Title = x.Title,
                Average = (int?)x.Ratings.Average(y => y.RatingValue)
        }).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
0 голосов
/ 21 января 2019

и, наконец, это код, работающий хорошо:

var data = _moviesDbContext.Movies.Include(x => x.Ratings)
            .Select(x => new MovieRating
            {
                Id = x.Id,
                Title = x.Title,
                Average = x.Ratings.Average(y => y.RatingValue)
            }).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();

        return data;

Проблема заключалась в создании анонимного типа в select, поэтому эта строка решает проблему: .Select (x => new MovieRating

И это полный код метода и нового класса, который я создал для сопоставления полей выбора с конкретным типом:

public class MovieRepository : IMovieRepository
{
    private readonly MovieDbContext _moviesDbContext;
    public MovieRepository(MovieDbContext moviesDbContext)
    {
        _moviesDbContext = moviesDbContext;
    }

    public IEnumerable<Movie> GetAll()
    {
        return _moviesDbContext.Movies;
    }

    public IEnumerable<MovieRating> GetTopFive()
    {
        var result = _moviesDbContext.Movies.Include(x => x.Ratings)
                    .Select(x => new MovieRating
                    {
                        Id = x.Id,
                        Title = x.Title,
                        Average = x.Ratings.Average(y => y.RatingValue)
                    }).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();

        return result;
    }
}

public class MovieRating
{
    public int Id { get; set; }
    public string Title { get; set; }
    public decimal Average { get; set; }
}
0 голосов
/ 20 января 2019

Попробуйте следующим образом:

public IEnumerable<Movie> GetTopFive()
{
    var result = _moviesDbContext.Ratings.GroupBy(r => r.MovieId).Select(group => new
        {
            MovieId = group.Key,
            MovieTitle = group.Select(g => g.Movie.Title).FirstOrDefault(),
            AvgRating = group.Average(g => g.RatingValue)
        }).OrderByDescending(s => s.AvgRating).Take(5).ToList();
    return result;
}

Это исключит фильмы без рейтингов.

Но если вы сделаете следующее (как ответ artista_14):

public IEnumerable<Movie> GetTopFive()
{
    var result = _moviesDbContext.Movies.GroupBy(x => new { x.Id, x.Title })
        .Select(x => new {
            Id = x.Key.Id,
            Title = x.Key.Title,
            Average = x.Average(y => y.Ratings.Sum(z => z.RatingValue))
    }).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
    return result;
}

это будет включать в себя фильмы без рейтинга.

Примечание. Я вижу, что ваш класс модели Rating не содержит какого-либо свойства навигации Movie. Пожалуйста, добавьте это следующим образом:

public class Rating
{
    public int Id { get; set; }
    public int MovieId { get; set; }
    public int UserId { get; set; }
    public decimal RatingValue { get; set; }

    public Movie Movie { get; set; }
}
...