SuperJMN
SuperJMN

Reputation: 13972

Trying to create a tree of nodes with LINQ to SQL produces NotSupportedException

I have the following code that works perfectly inside LINQPad as you can see in the screenshot. Please, notice the Results part in the bottom part of the screen, where the tree of nodes is shown:

LINQPad

But when I run it in my application, it shows the following exception:

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)

I guess it's the Children = null in the inner initialization. What am I supposed to do to create a node without children?

This is the full code:

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; }
}

Upvotes: 1

Views: 61

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205549

This is EF6 specific LINQ to Entities projection limitation.

You can't use Children = null because of the aforementioned runtime exception. Enumerable.Empty<T>(), new List<T>, new T[] are also not allowed. And if you omit that line, then you get another exception (requirement):

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.

Luckily there is a simple trick - create a derived type and use it in the projection where you need to omit the Children. For instance:

class LeafNodeDto : NodeDto { }

and then on level 3:

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

Upvotes: 3

Related Questions