尝试使用 LINQ to SQL 创建节点树会产生 NotSupportedException
Trying to create a tree of nodes with LINQ to SQL produces NotSupportedException
如您在屏幕截图中所见,我有以下代码可以在 LINQPad 中完美运行。请注意屏幕底部的 Results 部分,其中显示了节点树:
但是 当我在我的应用程序中 运行 它时,它显示以下异常:
System.NotSupportedException Unable to create a null constant value of
type
'System.Collections.Generic.IEnumerable`1[[EverGas.Back.Domain.Temp.NodeDto,
EverGas.Back.Domain.Temp, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]'. Only entity types, enumeration types or
primitive types are supported in this context. en
System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter
parent, ConstantExpression linq)
我猜是内部初始化中的Children = null
。我应该怎么做才能创建没有 children 的节点?[=15=]
这是完整代码:
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 = null
。 Enumerable.Empty<T>()
、new List<T>
、new T[]
也是不允许的。如果省略该行,则会出现另一个异常(要求):
System.NotSupportedException: `The type 'Namespace+NodeDto' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.
幸运的是,有一个简单的技巧 - 创建派生类型并在需要省略 Children
的投影中使用它。例如:
class LeafNodeDto : NodeDto { }
然后在第 3 层:
Children = level3.Select(x => new LeafNodeDto // <--
{
Id = x.ID_PRODUCTO,
Text = x.DE_PRODUCTO,
}),
如您在屏幕截图中所见,我有以下代码可以在 LINQPad 中完美运行。请注意屏幕底部的 Results 部分,其中显示了节点树:
但是 当我在我的应用程序中 运行 它时,它显示以下异常:
System.NotSupportedException Unable to create a null constant value of type 'System.Collections.Generic.IEnumerable`1[[EverGas.Back.Domain.Temp.NodeDto, EverGas.Back.Domain.Temp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'. Only entity types, enumeration types or primitive types are supported in this context. en System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
我猜是内部初始化中的Children = null
。我应该怎么做才能创建没有 children 的节点?[=15=]
这是完整代码:
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 = null
。 Enumerable.Empty<T>()
、new List<T>
、new T[]
也是不允许的。如果省略该行,则会出现另一个异常(要求):
System.NotSupportedException: `The type 'Namespace+NodeDto' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.
幸运的是,有一个简单的技巧 - 创建派生类型并在需要省略 Children
的投影中使用它。例如:
class LeafNodeDto : NodeDto { }
然后在第 3 层:
Children = level3.Select(x => new LeafNodeDto // <--
{
Id = x.ID_PRODUCTO,
Text = x.DE_PRODUCTO,
}),