使用EF Core将SQL转换为Linq

时间:2019-01-20 17:13:12

标签: c# entity-framework linq-to-sql .net-core repository-pattern

我正在使用.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,但无法正常工作。

对于将“ GetTopFive”方法的查询转换为LINQ的任何帮助,我将不胜感激。

谢谢

3 个答案:

答案 0 :(得分:2)

尝试这个-

Map<String, BigDecimal[]> stringMap

答案 1 :(得分:1)

尝试如下:

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; }
}

答案 2 :(得分:0)

最后这是运行良好的代码:

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; }
}