【问题标题】:Join Error | Unable to create a constant value of type only primitive加入错误 |无法创建仅原始类型的常量值
【发布时间】:2018-08-28 19:11:13
【问题描述】:

这里的 LINQ 非常新。

我的表(TableA)中有以下数据:

ID  Name      SubmissionNo
1   Jim       A-1
2   Andy      A-2
3   Rick      A-2
4   Mary      A-3
5   Zim       A-4
6   Loren     A-1

然后我需要创建一个查询,允许我从该表中获取那些具有重复提交编号的记录。

到目前为止,这是我的解决方案(上下文是数据库上下文):

var duplicates = (from tbl in Context.TableA.AsNoTracking()
                  group tbl by tbl.SubmissionNo into grp
                  select new { count = grp.Count(), submissionNo = grp.Key})
                 .Where(x => x.count > 1)
                 .OrderBy(y => y.submissionNo).ToList();

变量 duplicates 然后包含记录:

count  submissionNo
2      A-1
2      A-2

然后我编写主查询,这将允许我从 TableA 中获取所有具有重复提交的记录

var myList = (from tbl in Context.TableA.AsNoTracking()
              join dup in duplicates on tbl.SubmissionNo equals dup.submissionNo
              select new 
              { 
                ID = tbl.ID, 
                Name = tbl.Name, 
                SubmissionNo = tbl.SubmissionNo 
              })
              .ToList();

然后我得到一个关于 myList 查询的错误

无法创建“匿名类型”类型的常量值。此上下文仅支持原始类型或枚举类型。

我认为必须有更好的方法来做到这一点,就像上面的表A一样,我实际上想要以下结果:

ID  Name      SubmissionNo
1   Jim       A-1
2   Andy      A-2
3   Rick      A-2
6   Loren     A-1

【问题讨论】:

  • 嗨@Zysce - 我确实检查了提供的链接,但它没有做我想要的同样的事情。
  • 仅使用重复项作为提交编号列表,然后在您的最后一个 Linq 查询中尝试使用 where list contains
  • 如果您在 Duplicates 中不执行 ToList,是否也会出现此错误,因此如果您让 Duplicates 的类型为 IQueryable,而不是 List?

标签: c# entity-framework linq


【解决方案1】:

您的第一个查询稍作修改,包含您需要的所有信息:

var myList  = from tbl in Context.TableA.AsNoTracking()
              group tbl by tbl.SubmissionNo into grp
              where grp.Count() > 1
              from item in grp
              select new
              { 
                  count = grp.Count(),
                  submissionNo = grp.Key,
                  item.Name,
              );

模式group into grp - from item in grp 是一种常用的查询模式,用于对项目进行分组,然后再次展平该组,同时与组数据保持联系(如Count()Key)。

现在您不再需要加入,也不会发生异常。顺便说一句,异常告诉您 EF 只能处理原始类型集合(int 等)的连接,因为它必须将整个表达式转换为 SQL。像TableA 这样的丰富对象根本没有翻译。

顺便提一下,可以通过去掉重复的Count()来改进查询:

var myList  = from tbl in Context.TableA.AsNoTracking()
              group tbl by tbl.SubmissionNo into grp
              let count = grp.Count()
              where count > 1
              from item in grp
              select new
              { 
                  count = count,
                  submissionNo = grp.Key,
                  item.Name,
              );

这将生成一个更有效的 SQL 语句,其中包含一个 COUNT 而不是两个。

【讨论】:

    【解决方案2】:

    由于 Entity Framework 不支持将内存中的对象集合与数据库集合连接起来,因此常见的解决方法是使用 Contains 进行过滤。

    首先,您需要获取要过滤的 ID:

    var duplicates = (from tbl in Context.TableA.AsNoTracking()
                      group tbl by tbl.SubmissionNo into grp
                      select new { count = grp.Count(), submissionNo = grp.Key})
                     .Where(x => x.count > 1)
                     .OrderBy(y => y.submissionNo)
                     .ToList();
    var duplicateIds = duplicates.Select(x => x.submissionNo).ToList();
    

    然后更改您的查询以执行WHERE...IN 而不是JOIN

    var myList = (from tbl in Context.TableA.AsNoTracking()
                  where duplicateIDs.Contains(tbl.SubmissionNo)
                  select new 
                  { 
                    ID = tbl.ID, 
                    Name = tbl.Name, 
                    SubmissionNo = tbl.SubmissionNo 
                  })
                  .ToList();
    

    【讨论】:

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