A few things you can't do with EF queries which you won't find out until runtime

Naturally, these are on my mind because my hand still stings from getting slapped by the runtime when I tried to do this.

LINQ to Entities does not support projecting into known types structures.

Note, I tried this first with a structure, then saw the forum thread which I quoted below that I apparently misconstrued and landed on the wrong  conclusion. The post stopped me from experimenting further. I have since edited the post to be improve its accuracy. Thanks to Larry Parker for pointing out the gap.

If you have a type or struct defined such as:

Public Structure KeyListItem
 Public ID As IntegerPublic
 Name As String
End Structure

and are doing a query that will project out an ID and a Name, this is the natural way to write the query, given some experience with LINQ to [anything (including LINQ to SQL) but Entities].

Dim custs = From cust In context.Customers _
Select New KeyListItem With {.ID = cust.ContactID, .Name = cust.Name}

The compiler is fine with this because at compile time, it's merely a LINQ query.

However when you execute this query, you will get the error:

Only parameterless constructors and initializers are supported by LINQ to Entities.

LINQ to Entities can't construct a new KeyListItem structure on the fly with the ID and Name parameters. 

Here's an explanation of why this is the behavior for LINQ to Entities from Sushil Chordia on the DP team (from this forum thread).

The idea of supporting only parameter-less constructor was one of the hard decisions we made as a product team. The main idea with this approach was we shouldn't open up new surface area in LINQ over Entities that is not supported by EDM. EDM in general doesn't allow you to construct in random objects (using the NEW constructor in eSQL). To make it consistent with the whole stack, we decided to implement it like wise. Limiting the constructions only to:
      - Parameterless constructors 
      - Anonymous types (as it’s the only way to do multi-project in LINQ over Entities)

The query will work if you project into a class, not a structure. If you must use a structure then, instead you need to go the long way around with this.

Dim custs = From cust In context.Customers_
            Select cust.ContactID, cust.Name 
Dim custlist = New List(Of KeyListItem) 
For Each cust In custs
 custlist.Add(New KeyListItem 
              With {.ID = cust.ContactID, .Name = cust.FullNameAlpha}) 
Next

Okay, now the next thing you might accidentally try if your mind is wandering is to use custom properties from your partial classes in queries.

In my model I have a firstname property and a lastname property. I got sick of concatenating them, so I cleverly created two new properties in the entity's partial class: FullName and FullNameAlpha. A long long time ago, I got over the fact that I couldn't pull this off in the model and I'm extremely happy that this scenario is being targeted for v2.

So I'm happily coding along and writing a query where I want to return the FullNameAlpha field and sorted.

Because LINQ depends on the compiled classes to let us code with Intellisense, it's fine with me using the FullNameAlpha property in my query

Dim custs = From cust In .Customer _
                   Order By cust.FullNameAlpha _
                   Select cust.ContactID, cust.FullNameAlpha

But of course FullNameAlpha is not part of the model, so when EF tries to compile the query, it throws the obvious exception:

The specified type member 'FullNameAlpha' is not supported in LINQ to Entities.
Only initializers, entity members, and entity navigation properties are supported.

Oops. Yeah, right, I knew that!

So what that means is I still have to freaking concatenate the first name and last name in my query.

But there's another rule to watch out for which is a LINQ rule, not LINQ to Entities. When you create an on the fly property in a projection and your are doing so with a function, LINQ cannot figure out what to call that property, so you must name it as I have done here by using the variable name "fullname".

Dim custs = From cust In .Customer _
                   Order By cust.FullNameAlpha _
                   Select cust.ContactID, fullname = cust.LastName.Trim & "," & cust.FirstName

Otherwise you will get the LINQ error:

(VB) Range variable name can be inferred only from a simple or qualified name with no arguments

(C#)  Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.

I imagine I'll repeat these errors over and over and have to be reminded by the thrown exceptions over and over.

#1 Kristofer on 8.18.2008 at 12:04 AM

Wow, that is a pretty serious limitation, yet something basic that works fine in Linq2SQL.EF allows projecting into _anonymous_ types, but not into other types already defined elsewhere in a project, in the .net framework itself (e.g. KeyValuePair) etc......what were they thinking?

#2 Matthieu MEZIL on 8.18.2008 at 4:33 AM

Hi Julie,Instead of creating a list, why don't you use AsEnumerable method?

#3 Julia Lerman on 8.18.2008 at 6:29 AM

@matthieu- the resulting IEnumerable will still be <anonymous type> which doesn't suit my purposes.

#4 Larry Parker on 8.19.2008 at 9:06 AM

Try changing the KeyListItem type from a structure to a class.That worked for me, but you are correct -- it does seem to be inconsistent from LINQ to SQL since structs work.Personally I favor classes over structures for my concrete types when dealing with LINQ because I can check if they are null (something you can't do with a structure).-Larry

#5 Julia Lerman on 8.19.2008 at 9:17 AM

Larry,As soon as I tried to use that list for databinding, I realzied the type wanted to be a class. The point of the post, of course, was more about the limitation of the query than best practices for structures vs. classes. ;-)

#6 Larry Parker on 8.21.2008 at 12:42 PM

Hi Julie,Your post was a bit misleading: "LINQ to Entities does not support projecting into known types."That's not really true.If your known type is a class, you can use LINQ to Entities to project into it.-Larry

#7 Craig Stuntz on 8.26.2008 at 5:40 PM

Here's another. If you do .Where after .Order, you may lose the ordering (http://msdn.microsoft.com/en-us/library/bb896317.aspx#OrderingInfoLost). You learn this when you try to do .Take and LINQ to Entities complains at runtime that it doesn't support this on un-ordered data.

#8 Beth on 2.19.2009 at 8:30 PM

Here's another limitation (same parameterless constructor error) where you can do this with LINQ to SQL but not Entities unfortunately. This definitely tripped me up when moving from L2S to L2E.Dim db As New NorthwindEntitiesDim recentHiresXML = <?xml version="1.0"?> <employees> <%= From emp In db.Employees _ Where emp.HireDate > #1/1/1990# _ Order By emp.HireDate _ Select <employee><lastname><%= emp.LastName %></lastname><firstname><%= emp.FirstName %></firstname><city><%= emp.City %></city><region><%= emp.Region %></region></employee> %> </employees>You have to write it in 2 separate queries if you use EF.Dim recentHires = From emp In db.Employees _Where emp.HireDate > #1/1/1990# _Order By emp.HireDate _Select empDim recentHiresXML = <?xml version="1.0"?> <employees> <%= From emp In recentHires.ToList() _ Select <employee><lastname><%= emp.LastName %></lastname><firstname><%= emp.FirstName %></firstname><city><%= emp.City %></city><region><%= emp.Region %></region></employee> %> </employees>

#9 Julia Lerman on 2.19.2009 at 8:35 PM

Beth - that's one I never would have found. I still have to take some time to play with and learn xml literals!

#10 Beth on 2.19.2009 at 9:04 PM

Heh - oh come on! It's super easy. It's like VFP's TEXTMERGE on steroids ;-)

Leave a Comment