【问题标题】:Linq returns list or single objectLinq 返回列表或单个对象
【发布时间】:2010-09-28 20:15:18
【问题描述】:

我有一个像这样的 Linq to Entities 查询:

var results = from r in entities.MachineRevision
              where r.Machine.IdMachine == pIdMachine
                 && r.Category == (int)pCategory
              select r;

通常,我使用下面的代码来检查是否返回了一些结果:

if (results.Count() > 0)
{
    return new oMachineRevision(results.First().IdMachineRevision);
}

但是,我在 if 条件下得到 NotSupportedException

错误消息是:无法创建“闭包类型”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。

请注意,pCategory 是 Enum 类型。

【问题讨论】:

    标签: c# linq .net-3.5 enums


    【解决方案1】:

    编辑:根据您的更新,该错误可能与您的实体类中的枚举有关。有关更多信息和解决方法,请参阅此blog entry。我将保留我原来的答案作为对您的查询语法的改进。

    尝试使用 FirstOrDefault 选择查询本身中的第一个实体,然后检查结果是否为空。

    int compareCategory = (int)pCategory; // just a guess
    var result = (from r in entities.MachineRevision
                  where r.Machine.IdMachine == pIdMachine
                     && r.Category == compareCategory
                  select r).FirstOrDefault();
    
    if (result != null)
    {
         return new oMachineRevision(result.IdMachineRevision);
    }
    

    【讨论】:

    • 仍然不起作用,因为我们正在尝试对实体对象(即 linq 语句返回的内容)而不是 IEnumerable 执行 FirstOrDefault() 方法。
    • Select 总是返回一个 IEnumerable,请参阅此处的文档 msdn.microsoft.com/en-us/library/bb548891.aspx。您确定示例与您的代码完全相同吗?
    • 我的错误,对此我深表歉意。为了简化代码,我删除了一个枚举,就像 tvanfosson 注意到我收到的错误消息一样。谢谢大家,很抱歉误导了您。
    【解决方案2】:

    为什么不直接使用 FirstOrDefault() 来检查 null 呢?我看不到查询计数然后取第一个元素的好处。

    【讨论】:

    • 我明白你的意思。但是,如果我使用 FirstOrDefault(),我仍然会收到 NotSupportedException,因为我试图在实体对象(即 Linq 语句返回的内容)上执行该方法,而不是在 IEnumerable 上。
    【解决方案3】:

    在 linq 的标准实现中,运算符“select”和“where”映射到返回 IEnumerable 或 IQueryable 的方法。因此,使用标准 linq 方法时,应始终从查询中返回 IEnumerable,而不是单个对象。

    但是作为 linq 运算符候选的 linq 方法不限于返回 IEnumerables 的方法,任何返回任何值的方法都可以选择。

    如果您有名为“Select”和“Where”的实例方法返回单个对象,或者有特定于您的类并返回单个对象的扩展方法,这些方法将被使用,而不是标准 linq 方法。

    我的猜测是,您的类中定义的“Select”或“Where”方法正在使 linq 返回单个值而不是 IEnumerable<T>

    【讨论】:

      【解决方案4】:

      我不知道会根据查询结果创建不同的匿名对象。我猜他们只是希望结果是 IEnumerable 类型的

      使用 foreach 怎么样?

      var results = from r in entities.MachineRevision
                    where r.Machine.IdMachine == pIdMachine
                       && r.Category == pCategory
                    select r;
      
      foreach( var r in results )
      {
          yield return new oMachineRevision( r.IdMachineRevision );
      }
      

      【讨论】:

        【解决方案5】:

        这也适用于所有隐式类型。我必须承认我一直忘记这一点,这就是我看到这篇文章的原因。

        如果你有

        class ClassA {
                       ...
        
                       private string value;
        
                       ...
        
                       public static implicit operator string(ClassA value)
                       {
                            return value.ToString();
                       } 
        
                      ...
        }
        

        您需要将类显式转换为字符串以进行比较。

        所以我通常这样做

            var myClassAStr = myClassA.ToString();
        
            var x = (from a in entites where a.ValToCompare == myClassAStr select a).first();
        
        // do stuff with x
            ...
        

        【讨论】:

        • 其实我一般用a.ValToCompare.Equals(myClassAstr)
        【解决方案6】:

        尝试使用

        IENumerable<MachineRevision> results = from r in entities.MachineRevision
        ...
        

        改为。

        我认为它是导致您的问题的 var。

        【讨论】:

          【解决方案7】:

          编辑:

          阅读错误信息。 “无法创建‘闭包类型’类型的常量值。此上下文仅支持原始类型(‘例如 Int32、String 和 Guid’)。”

          其中一个比较是与不是 int、string 或 guid 的类型。我猜是类别。

          r.Machine.IdMachine == pIdMachine && r.Category == pCategory
          

          有趣的是,LinqToSql 将允许这种构造。不知道为什么 LinqToEntities 不支持这个。

          【讨论】:

            【解决方案8】:

            我认为您还可以使用 lambda 表达式以另一种更简单的方式选择您想要的项目。

            var result = entities.MachineRevision
                             .Where(x => x.Machine.IdMachine == pIdMachine)
                             .Where(y => y.Category == (int)pCategory)
                             .FirstOrDefault();
            
            if (result != null)
            {
                 return new oMachineRevision(result.IdMachineRevision);
            }
            

            然后照常进行

            【讨论】:

            • 不起作用,因为“.Where(y => y.Category == (int)pCategory)”会产生错误。您需要在查询之前对 Enum 进行强制转换。 var iCategory = (int)pCategory;然后只需在查询本身中使用 iCategory。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多