#c# #.net #entity-framework #linq-to-sql
#c# #.net #entity-framework #linq-to-sql
Вопрос:
У меня есть следующий код, который отлично работает внутри LINQPad, как вы можете видеть на скриншоте. Пожалуйста, обратите внимание на часть результатов в нижней части экрана, где показано дерево узлов:
Но когда я запускаю его в своем приложении, оно показывает следующее исключение:
Система.NotSupportedException Не удается создать нулевое постоянное значение типа ‘System.Коллекции.Общий.IEnumerable`1[[EverGas.Back.Domain.Temp.NodeDto, EverGas.Back.Домен.Temp, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null]]’. В этом контексте поддерживаются только типы сущностей, типы перечислений или примитивные типы. en System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(родительский преобразователь выражения, 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; }
}
Комментарии:
1. «отлично работает внутри LINQPad» От какого провайдера? Очевидно, не тот, который используется приложением. Итак, какой поставщик запросов вы на самом деле используете? LinqToSql — это не то же самое, что EF, а EF6 — это не то же самое, что EF Core. Сообщение об исключении звучит как EF6, но требует подтверждения.
2. Сбой в EF6. Работает с LINQPad (LINQ to SQL против SQL Azure)
3. В этом и был смысл. Если вы запустите запрос внутри LINQPad с использованием поставщика запросов EF6, он завершится с той же ошибкой.
Ответ №1:
Это ограничение проекции LINQ на объекты, специфичное для EF6.
Вы не можете использовать Children = null
из-за вышеупомянутого исключения во время выполнения. Enumerable.Empty<T>()
, new List<T>
, new T[]
также не разрешены. И если вы опустите эту строку, то получите другое исключение (требование):
Система.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,
}),