使用 linq 计算 EF Core 中的平均评分

Posted

技术标签:

【中文标题】使用 linq 计算 EF Core 中的平均评分【英文标题】:Using linq to calculate rating average in EF Core 【发布时间】:2021-12-23 11:16:12 【问题描述】:

用户可以按城市、品牌、服务类型和评级搜索公司。我已经开发了这样一个查询,但在评分部分出现错误。错误信息如下:

LINQ 表达式 'DbSet 。加入( 外部:数据库集, 内部:f => f.Id, outerKeySelector: c => c.FirmId, innerKeySelector: (f, c) => new TransparentIdentifier( 外部 = f, 内部 = c )) 。通过...分组( 来源:ti => ti.Outer, 键选择器:ti => 新 公司 = ti.Outer, 评级 = ti.Inner.Rate )' 无法翻译。要么以可翻译的形式重写查询,要么显式切换到客户端评估 通过插入对 AsEnumerable()、AsAsyncEnumerable() 的调用, ToList() 或 ToListAsync()。看 https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。

我在添加评分部分后遇到了这个错误。我怎样才能解决这个问题?我认为以这种方式提取数据不会有效。我应该如何开发这个地方?我还与您分享我用于查询的代码。

public async Task<IEnumerable<Firm>> GetFirmsForCustomerSearch(int cityId, int brandId, int serviceTypeId, int rate)
        
           var query = from firms in AracsalContext.Firm select firms;
            
            if (brandId > 0)
                query = from firms in query
                        join firmBrands in AracsalContext.Firmbrand on new  f1 = firms.Id, f2 = brandId  equals new  f1 = firmBrands.FirmId, f2 = firmBrands.BrandId 
                        select firms;

            if (serviceTypeId > 0)
                query = from firms in query
                        join firmServices in AracsalContext.Firmservice on new  f1 = firms.Id, f2 = serviceTypeId  equals new  f1 = firmServices.FirmId, f2 = firmServices.ServiceId 
                        select firms;

            if (cityId > 0)
                query = from firms in query
                        where firms.CityId == cityId
                        select firms;

            if (rate > 0)
            
                query = from firms in query
                        join comments in AracsalContext.Comment on firms.Id equals comments.FirmId
                        group new
                        
                            firm = firms,
                            rating = comments.Rate
                         by firms into g
                        where g.Average(r => r.rating) > rate
                        select g.Key;
            


            var result = await query.ToListAsync();
            return result;
        

非常感谢。 斋月

【问题讨论】:

【参考方案1】:

SQL 中的分组有局限性——您只能返回分组键和聚合结果。要返回整个记录,您必须加入原始查询增益。

if (rate > 0)

    filteredByRate = 
        from firms in query
        join comments in AracsalContext.Comment on firms.Id equals comments.FirmId
        group new
        
            rating = comments.Rate
         by new  firms.Id  into g
        where g.Average(r => r.rating) > rate
        select g.Key;

    query = 
        from films in query
        join f in filteredByRate on films.Id equals f.Id
        select films;

【讨论】:

报错信息中说可能有限制问题。我想你是对的。您的建议也解决了问题,谢谢。那么有没有办法在一个查询中聚合这些连接?这样做会导致性能问题吗? 应该没有性能问题,将查询分解为可理解的小部分是一种正常的方式。【参考方案2】:

您需要按一些 Id 进行分组,例如公司。Id

query = from firms in query
                        join comments in AracsalContext.Comment on firms.Id equals comments.FirmId
                        group new
                        
                            firm = firms,
                            rating = comments.Rate
                         by firms.Id into g
                        where g.Average(r => r.rating) > rate
                        select g.Key;

【讨论】:

当我这样做时,返回值是 int。而我希望返回值是坚定的。这就是我这样做的原因

以上是关于使用 linq 计算 EF Core 中的平均评分的主要内容,如果未能解决你的问题,请参考以下文章

无法从 Linq 查询 EF Core 访问字段值

如何使用 LINQ 和 EF Core 进行一对多

LINQ / EF Core 不能在查询中使用 string.Contains

使用 LINQ 查询语法 EF Core C# 的左外连接

插值字符串上的 Ef Core vs Linq

EF Core 2.0 中的动态访问表