尝试使用LINQ to SQL创建节点树会产生NotSupportedException

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尝试使用LINQ to SQL创建节点树会产生NotSupportedException相关的知识,希望对你有一定的参考价值。

我有以下代码在LINQPad中完美运行,如截图所示。请注意屏幕底部的结果部分,其中显示了节点树:

LINQPad

但是当我在我的应用程序中运行它时,它显示以下异常:

System.NotSupportedException无法创建类型为'System.Collections.Generic.IEnumerable`1 [[EverGas.Back.Domain.Temp.NodeDto,EverGas.Back.Domain.Temp,Version = 1.0.0.0,Culture =]的null常量值中性,PublicKeyToken = null]]'。在此上下文中仅支持实体类型,枚举类型或基元类型。 en System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent,ConstantExpression linq)

我想这是内部初始化中的Children = null。我应该怎么做才能创建一个没有孩子的节点?

这是完整的代码:

void Main()
{
    var query = from customer in EVG_T_M_SUJETO
                where customer.ID_SUJETO == 830
                from account in customer.EVG_T_G_CUENTA
                group account by customer
                into level1
                select new NodeDto
                {
                    Id = level1.Key.ID_SUJETO,
                    Text = level1.Key.DE_SUJETO,
                    Children = from cuenta in level1
                               from product in cuenta.EVG_T_G_CONTRATO
                               group product by cuenta
                        into level2
                               select new NodeDto
                               {
                                   Id = level2.Key.ID_CUENTA,
                                   Text = level2.Key.CD_CUENTA,
                                   Children = from cont in level2
                                              from link in cont.EVG_T_R_PRODUCTO_CONTRATO
                                              let prod = link.EVG_T_M_PRODUCTO
                                              group prod by cont
                                       into level3
                                              select new NodeDto
                                              {
                                                  Id = level3.Key.ID_CONTRATO,
                                                  Text = level3.Key.CD_CONTRATO,
                                                  Children = level3.Select(x => new NodeDto()
                                                  {
                                                      Id = x.ID_PRODUCTO,
                                                      Text = x.DE_PRODUCTO,
                                                      Children = null,
                                                  }),
                                              }
                               }

                };

    query.ToList().Dump();
}

class NodeDto
{
    public int Id { get; set; }
    public string Text { get; set; }
    public IEnumerable<NodeDto> Children { get; set; }
}
答案

这是EF6特定的LINQ to Entities投影限制。

由于上述运行时异常,您无法使用Children = nullEnumerable.Empty<T>()new List<T>new T[]也是不允许的。如果省略该行,则会出现另一个异常(要求):

System.NotSupportedException:`类型'Namespace + NodeDto'出现在单个LINQ to Entities查询中的两个结构不兼容的初始化中。可以在同一查询中的两个位置初始化类型,但前提是在两个位置都设置了相同的属性,并且这些属性以相同的顺序设置。

幸运的是有一个简单的技巧 - 创建派生类型并在投影中使用它,你需要省略Children。例如:

class LeafNodeDto : NodeDto { }

然后在第3级:

 Children = level3.Select(x => new LeafNodeDto // <--
 {
     Id = x.ID_PRODUCTO,
     Text = x.DE_PRODUCTO,
 }),

以上是关于尝试使用LINQ to SQL创建节点树会产生NotSupportedException的主要内容,如果未能解决你的问题,请参考以下文章

使用 LINQ To SQL / SQL CE 创建表

在 EF Core 中使用表达式树会产生奇怪的 SQL 语句

如何使用 LINQ to SQL 创建通用数据访问对象 (DAO) CRUD 方法

C# Linq to sql 实现 group by 统计多字段 返回多字段

Linq-To-Sql ORM 更新一对多

使用 SQL Server Compact Edition 的 Linq-to-SQL