Tuesday, July 9, 2013

LINQ to Entites 'parameterless constructor' error

LINQ to Entities takes a different approach than LINQ to SQL in some areas.  In part this is a matter of wanting LINQ to Entities to be more explicit about the boundary between what parts of your query execute on the server and what part execute on the client.

With LINQ to SQL, for instance, it is possible to write a LINQ query which not only involves data from the server and functions on the server but also functions that can only be executed on the client and to mix them in together.  The LINQ to SQL provider will then do its best to untangle things and execute the parts that it can on the server and other parts on the client.  This is nice because it is easy to just write whatever query you want and if at all possible it will work.  On the other hand, it's not so nice if you accidentally write a query where the only part which can execute on the server is the most basic thing that returns all the data in one or more tables and then have all the filtering happen on the client (with very nasty perf consequences).

With LINQ to Entities, the boundaries are more explicit.  When you write a LINQ query against a LINQ to Entities IQueryable implementation, the entire query executes on the server, and if some part of the query cannot be executed on the server, then an explicit boundary must be created with something like ToQueryable() or ToList().  Once that query is executed and the data retrieved, then you can use LINQ to Objects to further refine the query if you so choose.  This way you explicitly know where your boundaries are, and it's easier to track down performance issues and the like.  One of the related limitations is that the select statement in LINQ to Entities can create anonymous types or other types as long as they have a default constructor and settable parameters.  This minimizes the chance that the select statement has major side effects.

As mentioned above, if you need to construct something which does not fit these constraints, then your best option is probably to have your linq to entities query return an anonymous type, and then wrap that with a linq to objects query which extracts the values from that type and calls the constructor on your other type:
var serverQuery = from ca in context.tb_carts
                          select new
                          {
                              ID = ca.tb_items.id,
                              Name = ca.tb_items.name,
                              Description = ca.tb_items.description,
                              CategoryName = ca.tb_items.tb_item_categories.name,
                              Price = ca.tb_items.price
                          };
IEnumerable cart = from ca in serverQuery.AsEnumerable()
                                                select new ItemDetails
                                                (
                                                    ca.ID,
                                                    ca.Name,
                                                    ca.Description,
                                                    ca.CategoryName,
                                                    ca.Price
                                                );

Digest from: msdn

No comments: