【问题标题】:Sequence contains more than one matching element序列包含多个匹配元素
【发布时间】:2017-12-28 12:07:11
【问题描述】:

当我尝试设置匹配条件的每个敷料项目的IsDefault 属性时,它会引发错误:

序列包含多个匹配序列。

(this.DressingItems
     .Where(xx => xx.DressingInfo.CatID == catId 
                        && xx.ProductID == this.ProductID)
     .Single()).IsDefault = false;

【问题讨论】:

    标签: c# linq-to-sql


    【解决方案1】:

    好吧,这个例外表明序列DressingItems 中至少有两个项目符合您的Where 条件。对Single 的调用随后会导致异常,因为它断言只有一项被传入。

    阅读你的问题让我觉得你想对输入序列的每个项目做一些事情,所以你可能会使用 foreach 循环:

    foreach(var item in this.DressingItems.Where(xx => xx.DressingInfo.CatID == catId && xx.ProductID == this.ProductID))
    {
        item.IsDefault = false;
    }
    

    【讨论】:

    【解决方案2】:
    this.DressingItems.Where(x=> x.DressingInfo.CatID == catId && 
                                    x.ProductID == this.ProductID).ToList()
                     .ForEach(item=>item.IsDefault = false);
    

    【讨论】:

    • 是的,你是对的。在List 上定义了一个扩展方法,但在我看来,这个语句很难阅读并且具有开车射击的优雅 =)
    • 你为什么这么说?是因为ForEach 中的资本F :) 吗?
    • 否 - 也许是大写 E :) 我个人的意见:linq 语句提供了一种以紧凑方式查询数据源的好方法,但 ForEach 扩展方法没有投影或序列上的选择。相反,它将元素传递给它的主体,在那里发生了一些事情并返回 void。它打破了模式:)
    【解决方案3】:

    Single 运算符的要点是断言给定序列只有一项。例如,通过主键检索特定实例时。

    我想你想改变任何符合条件的DressingItem 的状态,在这种情况下,你有一些选项,都涉及枚举结果集和执行一些行为。

    没有专门执行此操作的 LINQ 运算符,因为 LINQ 运算符是纯粹的。纯函数是没有副作用的函数,而这正是你想要做的。

    不过,List<T> 上有一个扩展方法允许这样做。例如

    this.DressingItems.Where(di => di.DressingInfo.CatID == catId
                                && di.ProductID == this.ProductID)
                      .ToList()
                      .ForEach(di => 
                      {
                          di.IsDefault = false
                      });
    

    或者你可以自己动手:

    public static class EnumerableExtensions
    {
        public static IEnumerable<T> ForEach<T>(
             this IEnumerable<T> source,
             Action<T> mutator)
        {
            var buffered = source.ToList();
            buffered.ForEach(mutator);
            return buffered;
        }
    }
    

    您可能会问为什么微软的人决定不将它添加到 BCL:我记得,我的想法是扩展方法与 foreach() { } 构造在打字方面无论如何都不会产生太多好处,而且它不会在模棱两可方面根本没有帮助。所有其他运算符都没有副作用,而这个运算符是专门为诱导它们而设计的。

    【讨论】:

      【解决方案4】:

      这是Single方法抛出的InvalidOperationException。

      该方法应该只返回一个元素,请检查您在查询中使用的条件。

      但是当它找不到任何元素时也会抛出异常

      【讨论】:

        【解决方案5】:

        您在 this.DressingItems 中有多个项目与给定的 CatId 和 Product Id 匹配。

        如果您确定必须有一个(单个),那么您必须查看 this.DressingItems 是如何加载的。

        如果预计有多个,则必须使用 foreach 设置值。

        【讨论】:

          【解决方案6】:

          由于您正在寻找一个单一的班轮,您可以创建自己的方法来做到这一点。

          public static void DoActionForEachElement<T>(IEnumerable<T> items, Func<T, bool> predicate, Action<T> action)
          {
              foreach (var item in items)
              {
                  if (predicate(item))
                      action(item);
              }
          }
          

          然后调用它

          DoActionForEachElement(
                         DressingItems,
                         xx => xx.DressingInfo.CatID == catId && xx.ProductID == ProductID,
                         x => x.IsDefault = false);
          

          这样您不必先将结果从Where 转换为List。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多