【问题标题】:I want to convert this foreach loop to a LINQ statement我想将此 foreach 循环转换为 LINQ 语句
【发布时间】:2014-07-25 15:27:33
【问题描述】:

无论如何,我在 linq 方面都不是很擅长,但我通常对这类问题没有意见。我想将此 foreach 语句转换为 LINQ 语句:

var existingKeys = new List<int>();
foreach (var taskKey in request.Keys)
        {
             existingKeys.AddRange(_context.WebTaskGroups
                 .Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
                 .Select(x => x.TaskGroupNameKey));
        }

我认为这样做可以:

var existingKeys = request.Keys.ForEach(taskKey => _context.WebTaskGroups
        .Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
        .Select(x => x.TaskGroupNameKey));

这显然返回一个 void 而不是一个列表... 这个:

  var existingKeys = request.Keys.Select(taskKey => 
            _context.WebTaskGroups
            .Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
            .Select(keys => keys.TaskGroupNameKey));

给我一​​个“IEnumerable>。那么我在这里缺少的秘诀是什么?

【问题讨论】:

  • 假设您在 Visual Studio 中,Resharper(一个代码质量插件)实际上非常擅长识别可以转换为 LINQ 语句的循环。
  • IEnumerable&lt;IQueryable&lt;int&gt;&gt; 转换为 IEnumerable&lt;int&gt; 应该可以使用 SelectMany 而不是第一个 Select。
  • 基本上你正在执行 N 个查询,每个键一个。你不应该那样做;您应该执行 one 查询以获取您想要的所有项目。对数据库执行所有这些往返行程尤其成问题。
  • @Robert 为什么要花大量时间尝试让解决方案发挥作用,因为您知道自己将要丢掉那些工作并做一些完全不同的事情?
  • @Robert 你开始的方法已经工作了。这并不是说您没有可行的解决方案。使用 LINQ 尝试删除您所拥有的循环绝不会改变代码的语义,这纯粹是为了美观。将代码更改为执行一次查询而不是 N 实际上是一种语义更改。

标签: c# linq entity-framework


【解决方案1】:

您不应该首先执行 N 个数据库查询。使用 LINQ 执行这 N 个查询而不是 foreach 循环并不能解决该核心问题。

您需要重新概念化您的查询,以便您只需一个查询即可获取所需的所有数据。在这种情况下,这意味着获取与您的 集合 键匹配的所有项目,而不是尝试匹配单个键然后执行 N 个这些查询。

var requestedKeys = request.Keys;
var existingKeys = _context.WebTaskGroups
                 .Where(x => x.TaskGroupNameKey == key && 
                     requestedKeys.Contains(x.TaskKey))
                 .Select(x => x.TaskGroupNameKey))
                 .ToList();

【讨论】:

  • +1 用于通知查询次数!
  • 那么在查询中使用之前重新分配keys属性有什么好处呢?
  • @Robert 一些查询提供程序可以在您不需要这样做的情况下正常工作,有些则不会,所以我这样做是因为我不确定您使用的是哪个查询提供程序。
  • 这可能是一个愚蠢的问题,但“查询提供程序”是对我正在使用的 ORM 的引用吗?
  • 好的,知道了,我正在使用 EF。
【解决方案2】:
var existingKeys = request
    .SelectMany(r => r.Keys)
    .SelectMany(tk =>
        _context.WebTaskGroups
            .Where(x.TaskGroupNameKey == key && x.TaskKey == tk)
            .Select(x => x.TaskGroupNameKey))
    .ToList();

【讨论】:

    【解决方案3】:
    var existingKeys = _context.WebTaskGroups
                 .Where(x => x.TaskGroupNameKey == key && request.Keys.Contains(x.TaskKey))
                 .Select(x => x.TaskGroupNameKey)
                 .ToList();
    

    【讨论】:

      【解决方案4】:

      ForEach 返回一个 void:http://msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.110).aspx

      ForEch:对 List 的每个元素执行指定的操作。

      那么怎么做,就是为request.Keys列表中的每一项执行动作添加到existingKeys列表中。

      例如:

      request.Keys.ForEach(taskKey => 
               existingKeys.AddRange(_context.WebTaskGroups
                   .Where(x => x.TaskGroupNameKey == key && x.TaskKey == taskKey)
                   .Select(x => x.TaskGroupNameKey));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 2010-11-19
        • 1970-01-01
        • 2014-03-16
        • 1970-01-01
        相关资源
        最近更新 更多