Entity Framework 平均分组

Entity Framework average with grouping

正在尝试为以下列添加平均值:经度和纬度

这是我的 SQL 查询:

SELECT
    ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ID, 
    r.StateProvinceRegion, 
    AVG(s.Longitude) AS Longitude, 
    AVG(s.Latitude) AS Latitude
FROM
    RestaurantAddress r 
INNER JOIN
    Restaurant s ON s.RestaurantId = r.RestaurantId
GROUP BY
    StateProvinceRegion

Entity Framework代码:

public VersionResponse GetRegions()
{
    var regionList = from restaurantAddress in _context.RestaurantAddress
                     join restaurant in _context.Restaurant on restaurantAddress.RestaurantId equals restaurant.RestaurantId
                     select new { restaurantAddress.StateProvinceRegion, 
                                  restaurant.Longitude, restaurant.Latitude, 
                                  average = (new double?[] { restaurant.Longitude, restaurant.Latitude }).Average() 
                                };

    return new VersionResponse()
               {
                    Data = regionList
               };
}

目前,当我尝试获取经度和纬度的平均值时,我收到一个 http 500 错误,指出处理 LINQ 表达式时出现问题 AsQueryable<Nullable<double>>(new Nullable<double>[]

有什么方法可以在 Entity Framework 的查询中添加平均值?

您需要在中添加 GroupBy LINQ 调用..

我通常 with/feel 更习惯使用方法语法而不是查询语法,所以这可能有点不对:

select ( ... your existing query ...)
group by StateProvinceRegion into g
select new {
  StateProvinceRegion = g.Key,
  AvgLat = g.Average(x => x.Latitude),
  AvgLong = g.Average(x => xLongitude)
}

当您在 LINQ 中对某些内容进行分组时,您不会得到 SQL 这个词意义上的分组; SQL 获取详细信息行,在 GROUP BY 中指定的键列上分组,然后 运行s 在 select 和 returns 中指定的聚合只是键和聚合结果. LINQ 比这更早停止并保留 SQL 丢弃的细节,但您必须直接处理细节以 运行 聚合 - LINQ 所做的就是将事物列表划分为事物列表,因此 address/lat/long 的原始列表变得像 Dictionary<(address), List<(address, last, long)>> - 也就是说对于每个唯一地址都有一个关联具有该地址的所有 address/lat/long 列表。

地址存储在g.Key中,列表详细信息为g。这意味着您从密钥中检索地址,并使用典型的 list.Average(element => element.Property) 模式

计算例如平均纬度

在我看来,每家餐厅都有一个地址,而您想要每个州省地区所有餐厅的平均位置。如果您的餐厅有多个地址,则代码不会更改。

我的建议是获取每家餐厅及其地址,然后按 StateProvinceRegion 分组。使用 overload of GroupBy that has a parameter resultSelector.

在 StateProvinceRegion 的结果选择器中计算平均经度/纬度。

var result = dbContext.Restaurant.Join(dbContext.Address,

    restaurant => restaurant.RestaurantId, // from every Restaurant take the primary key
    address => address.RestaurantId,       // from every Address take the foreign key
                                           // to the Restaurant

    (restaurant, address) => new           // when they match, use the Restaurant and 
    {                                      // the Address to make one new object
        
        StateProvinceRegion = restaurant.StateProvinceRegion,
        Longitude = address.Longitude,
        Latitude = address.Latitude,
    })

    // Result: per restaurant its StateProvinceRegion and the Longitude and Latitude
    // of the Restaurant's Address

    // from the joinResult make groups that have equal value for StateProvinceRegion
    .GroupBy(joinResult => joinResult.StateProvinceRegion,

        // parameter resultSelector: take the StateProvinceRegion
        // and all Longitudes / Latitudes that have this StateProvinceRegion
        // to make one new object:
        (stateProvinceRegion, joinResultsWithThisStateProvinceRegion) => new
        {
            StateProvinceRegion = stateProvinceRegion,

            Longitude = joinResultsWithThisStateProvinceRegion
                .Select(joinResult => joinResult.Longitude)
                .Average(),

            Latitude = joinResultsWithThisStateProvinceRegion
                .Select(joinResult => joinResult.Latitude)
                .Average(),
        });

简单的comme bonjour!