C# LINQ,带有 JOIN 和 GroupBy 的脚本抛出异常

C# LINQ, script with JOIN and GroupBy throwing exception

我正在处理 .NET CORE 5 平台上的 LINQ 脚本以及 Entity Framework Core 5.0.8 脚本简单地与组一起左加入但出现异常,如果不应用组那么我可以看到结果...不确定我在拼图中遗漏了什么

异常

could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'

代码

var a1 =
  (from site in db.Sites
  join machine in db.Machines on site.SiteId equals machine.SiteId into sm
  from siteMachines in sm.DefaultIfEmpty()
  where site.SiteId == SiteId
  group siteMachines by site into groupedSiteMachines
  select new
      {
       listedSite = groupedSiteMachines.Key,
       SiteMachines = groupedSiteMachines.FirstOrDefault() == null? null : groupedSiteMachines
      }
  ).ToList() ;

您无法在 LINQ to Entities 中获取分组项目的第一个元素。考虑按以下方式重写查询:

var query = 
    from site in db.Sites
    where site.SiteId == SiteId
    from siteMachines in db.Machines.Where(machine => site.SiteId == machine.SiteId)
        .Take(1)
        .DefaultIfEmpty()
    select new
    {
        listedSite = site,
        SiteMachines = siteMachines
    };

.NET 5 中,GroupBy 未转换为 SQL 查询,您应该使用 AsEnumerable.ToListGroupBy 语句之前。

首先你应该从 SQL 中读取数据而不需要任何 GroupBy 语句,当数据接收到你的内存中时,使用 GroupBy.

Microsoft Reference

所以你有 SitesMachines,并且站点和机器之间存在一对多关系:每个站点上都有零个或多个机器,并且每个机器都打开正好一个Site,即外键SiteId所指的Site。

在我看来,您有一个值 siteId,并且您希望该站点的主键和该站点上的所有机器都具有该值。

每当你有一对多关系时,比如学校有零个或多个学生,客户有零个或多个订单,或者在你的情况下,网站有他们的机器,考虑使用其中一个重载共 Queryable.GroupJoin

int siteId = 42;

var siteWithItsMachines = dbContext.Sites

    // keep only the site with siteId
    .Where(site => site.Id == siteId)

    // To get the Machines on each Site, do a GroupJoin:
    .GroupJoin(dbContext.Machines,

    site => site.Id              // from each Site take the primary key
    machine => machine.SiteId,   // from each Machine take the foreign key

    // parameter resultSelector: from every Site with all Machines on this Site
    // make one new object:
    (site, machinesOnThisSite) => new
    {
        // Select the Site properties that you plan to use:
        Id = site.Id,
        Name = site.Name,
        Location = site.Location,
        ...

        Machines = machinesOnThisSite.Select(machine => new
        {
            // select the Machine properties that you plan to use:
            Id = machine.Id,
            Type = machine.Type,
            ...

            // not needed, you already got the value
            // SiteId = machine.SiteId,
        })
        .ToList(),
    });

为了提高效率,我没有 select 完整的站点和完整的机器,而是我打算使用的属性。