【问题标题】:Unable to create a constant value of type 'System.Tuple无法创建类型为“System.Tuple”的常量值
【发布时间】:2019-04-24 16:27:03
【问题描述】:

我正在尝试实现 c# linq 表达式,该表达式将允许我根据年份和月份提取数据。错误是在我的上下文的 where 方法中引发的。

我目前遇到错误

System.NotSupportedException: 'Unable to create a constant value of type 'System.Tuple`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. Only primitive types or enumeration types are supported in this context.'

Linq 表达式

var periodTuples = period.ToList() // gives you List<KeyValuePair<int, int[]>>
                .SelectMany(kvp =>
                    kvp.Value.Select(it2 => Tuple.Create(kvp.Key, it2))).ToHashSet(); // to optimize .Contains()


benchmark1Returns = GetViewService<MV_INDEX_PERFORMANCE>()
                .Where(x => x.Mtd != null && x.IndexId == benchMark1 && periodTuples.Contains(Tuple.Create(x.PriceDate.Year, x.PriceDate.Month))).Select(x => x.Mtd);

在我的上下文中定义的 Where 方法

public IEnumerable<T> Where(Expression<Func<T, bool>> predicate)
        {
            try
            {
                using (new TimedLogger(_perfLogger, GetCompletedText("Where")))
                {
                    return Authorize(_repo.Where(predicate).ToList(), AuthAccessLevel.Read);
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
                throw;
            }
        }

【问题讨论】:

  • Tuple.Create 无法翻译成 SQL。
  • 那怎么办

标签: c# entity-framework linq entity-framework-6


【解决方案1】:

尝试加入?

            var benchmark1Returns = GetViewService<MV_INDEX_PERFORMANCE>()
                .Where(x => x.Mtd != null && x.IndexId == benchMark1)
                .Join(periodTuples,
                    b1r => new { x = b1r.PriceDate.Year, y = b1r.PriceDate.Month },
                    tuple => new { x = tuple.Item1, y = tuple.Item2 },
                    (b, t) => b.Mtd);

【讨论】:

    【解决方案2】:

    EF6 不支持(无法转换为 SQL)Tuple.Create(和 Tuple&lt;&gt; 构造函数)、内存中集合连接、Contains 非原始类型的内存中集合以及许多其他类型。

    您的解决方案是将 (int year, int month) 对替换为原始类型表达式,如下所示:

    int period = 12 * year + (month - 1)
    

    并将其用于过滤,例如

    var periods = period.ToList() // gives you List<KeyValuePair<int, int[]>>
        .SelectMany(kvp => kvp.Value, (year, month) => 12 * year + (month - 1));
    

    然后在 LINQ 查询中

    periods.Contains(12 * x.PriceDate.Year + (x.PriceDate.Month - 1))
    

    请注意,在 LINQ to Entities 中查询 periods 不需要是 HashSet&lt;int&gt;(或 List&lt;int&gt; 等) - IEnumerable&lt;int&gt; 就足够了,因为它将在本地评估一次并转换为 SQL IN (val1, val2, ..., valN)标准。

    【讨论】:

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