views:

65

answers:

1

I'm trying to solve a problem similar to the one described here

http://stackoverflow.com/questions/1440289/initializing-strongly-typed-objects-in-linq-to-entities

only from totally the opposite direction. I have a number of functions in my repository, all of which return identically shaped data. The issue is my projection code:

select new pocoClass
 {
   // complex projection that is several pages long includes grabbing a graph of data
 }

at the moment it exists for each query in the repository. I'd tried moving it into an object initializer, but that gives me the dreaded "Only parameterless constructors and initializers are supported in LINQ to Entities." issue.

I did try splitting into two queries

var candidates = (from thing in _entities.whatever
  where (complex.stuff==true)
  select thing);

var final = (from thing in candidates.AsEnumerable()
  let x = thing.ITEMS.Where(blah=>blah.blah==param)
  let y = x.OTHERITEMS.FirstOrDefault()
  select new pocoClass(thing,x,y);

but here final is always null and the code in new pocoClass is never called. I've included the let x & y in the above because these always vary between each use of the projection.

So, do I have to go back to multiple copies of my projection or is there another way out of this ?

+2  A: 

I'm not sure it this is usable for you, but what I often do is create projection methods that take an IQueryable and return an IQueryable to translate from a domain object to a DTO. They look much like this:

public static IQueryable<CustomerDTO> ToCustomerDTO(
    IQueryable<Customer> customers)
{
    return
        from customer in customers
        select new CustomerDTO()
        {
           ...
        };
}

This allows me to have this projection in a single place. From several places in my business layer I call such a method.

There are a few things to note, though:

  • Make sure these projection methods don't contain any business logic. Having any use case specific filters would be bad.
  • Sometimes you have a DTO that contains a complex object graph that you want efficiently pull from the database in a single query. With a bit of creativity this is very often possible, but not when returning an IQueryable. In that case I return an array of DTOs.
  • I place those projection methods as static methods inside the DTO class. While this isn't a very clean design, it found out it makes the code very maintainable.

I hope this helps.

Steven
Almost - its the business logic issue - in my example the let statements which are evaluated for each customer prior to the projection.
Andiih
Actually thats enough to give me a solution. I've created a new simplified DTO intermediate class that I can project in place just by copying a half dozen values: each one being a whole EF entity. Then I use your solution to make the final projection out of those entities. Not sure how it will perform, but its certainly neater!
Andiih
@Andiih: You will have to use the SQL profiler to see how many queries are executed in the background. There is a good change that EF will execute many queries behind the covers. The technology -of course- has its limits. If you're not happy with the performance and have no clue about how to get this in a single query, perhaps I can help you with that. In that case, start a new question here at SO and drop a link to it here. Cheers
Steven