Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional projection with LINQ to Entities

I have a query over a single entity (with some navigation properties) and need to project them into a model for consumption by API clients. It looks basically like this:

repository.CreateQuery<Reviews>()
  .Where(/* criteria */)
  .Select(m => new
    {
      ID = m.ID,
      Reviewers = m.IsAnonymous 
        ? m.Reviewers.Take(1).Select(r => new { Name = "Anonymous" })
        : m.Reviewers.Select(r => new { Name = r.Name })
    })

LINQ to Entities fails to execute this at runtime. In the Visual Studio debugger, the exception message is "Specified method is not supported". In LinqPad, the inner exception is "The nested query is not supported. Operation1='Case' Operations2='Collect'".

Any ideas how to work around this? I'd rather not force the query to execute to get the objects in memory because the point of this conditional query is to solve a performance issue, so as far as I can tell I really need to solve this within the scope of the L2E query.

Update: the projected types aren't anonymous in my real application. I just used anonymous ones here because it was convenient to contrive the example. In similar fashion, the real queries involve a number of additional properties which mean a great deal more data coming from the mapped tables.

like image 660
Ben Collins Avatar asked Dec 18 '12 21:12

Ben Collins


1 Answers

You can use union to do what you want:

var query1 = repository.CreateQuery<Reviews>()
                       .Where(/* criteria */);
var queryAnonimous = query1.Where(m=>m.IsAnonymous)
                           .Select(m => new
                                        {
                                            ID = m.ID,
                                            Reviewers = m.Reviewers.Take(1).Select(r => new { Name = "Anonymous" })        
                                        })

var queryNotAnonymous =  query1.Where(m=>!m.IsAnonymous)
                               .Select(m => new
                                            {
                                                ID = m.ID,
                                                Reviewers = m.Reviewers.Select(r => new { Name = r.Name })
                                            })
var unionQuery = queryAnonimous.union(queryNotAnonymous);
like image 168
Kirill Bestemyanov Avatar answered Oct 14 '22 04:10

Kirill Bestemyanov