Попытка создать дерево узлов с помощью LINQ to SQL приводит к NotSupportedException

#c# #.net #entity-framework #linq-to-sql

#c# #.net #entity-framework #linq-to-sql

Вопрос:

У меня есть следующий код, который отлично работает внутри LINQPad, как вы можете видеть на скриншоте. Пожалуйста, обратите внимание на часть результатов в нижней части экрана, где показано дерево узлов:

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,
 }),