【问题标题】:How to refactor Linq Group By and Foreach statement into one Linq Query如何将 Linq Group By 和 Foreach 语句重构为一个 Linq Query
【发布时间】:2019-07-23 11:33:12
【问题描述】:

我在尝试将下面的 LINQ 查询重构为一个查询时遇到了一些麻烦:

// produces 8 results
            var qryResults =
                (from r in dbContext.Routes
                 join br in dbContext.BrokerRoutes on r.RouteId equals br.RouteId
                 join pr in dbContext.RoutePathFilters.Include(x => x.PathFilter) on r.RouteId equals pr.RouteId into paths
                 where br.Broker.ApiKey == apiKey
                 select new RouteTemplate
                    {
                        RouteId = r.RouteId,
                        Version = r.Version.Version,
                        Url = r.Url,
                        IsActive = r.IsActive,
                        Paths = paths.Select(x => x.PathFilter.FilterName).ToList()
                 })
                .AsNoTracking()
                .ToImmutableList();
// takes 8 results and turns that into 2 overall objects.
            var results = new List<RouteTemplate>();
            foreach (var r in qryResults)
            {
                if (results.All(x => x.RouteId != r.RouteId))
                {
                    r.Paths = qryResults
                        .Where(x => x.RouteId == r.RouteId)
                        .Select(x => x.Paths.First()).ToList();
                    results.Add(r);
                }
            }

rpaths 属性中保存的每个值重复。

我知道 foreach 可以合并到上面的 linq 查询中,但我已经尝试了几个小时。所以我很有趣知道它是否可能以及如何完成?

【问题讨论】:

  • 当您尝试直接在 ImmutableList 上使用 ForEach LINQ 方法时会发生什么?
  • @Stormhashe - 这提供了另一种选择 - ty - 让我试试看。
  • 酷,让我知道它是否有效。这就是我想做的事情,将 foreach 中的代码重构为一个方法,并使用 ForEach LINQ 方法将列表的每个元素传递给内部方法

标签: c# linq linq-to-entities entity-framework-core


【解决方案1】:

如果没有实际的数据库,我不确定这是否可行,但这是我的尝试:

var qryResults =
    (from r in dbContext.Routes
     join br in dbContext.BrokerRoutes on r.RouteId equals br.RouteId
     where br.Broker.ApiKey == apiKey
     join pr in dbContext.RoutePathFilters.Include(x => x.PathFilter) on r.RouteId equals pr.RouteId into paths
     group new { r, paths } by r.RouteId into rprg
     let r = rprg.First().r
     select new RouteTemplate {
         RouteId = rprg.Key,
         Version = r.Version.Version,
         Url = r.Url,
         IsActive = r.IsActive,
         Paths = rprg.Select(rpr => rpr.paths.First().PathFilter.FilterName).ToList()
     })
    .AsNoTracking()
    .ToImmutableList();

【讨论】:

  • 我又跑到这个issue里了,最简单的答案就是去掉投影语句,直接从rprg中选择。
  • 另外:rprg.First().r 将始终为集合中的每个对象分配相同的值。如果 versionurl 信息不同,则每个投影到 select 语句中的结果对象都会简单地覆盖它。
  • @IbrarMumtaz 您的代码仅将每组RouteId 的第一个RouteId 添加到results,与此LINQ 相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多