views:

72

answers:

3

What I currently have looks a bit like this:

if(userLikesBananas)
{
    return from fruit in basket
           select new Fruit
           {
               AteBanana = Bowl.Any(b => b.OwnedBy == user && b.Contains(fruit) && fruit.Type == FruitType.Banana),
               ...
               ...
               //lots of properties
               ...
           }
}
else
{
    return from fruit in basket
           select new Fruit
           {
               AteBanana = Bowl.Any(b => b.Contains(fruit)),
               ...
               ...
               //lots of properties
               ...
           }
}

Admittedly the example makes absolutely no sense, but the principle is that I want to change the conditions of a properties selection based on arbitrary criteria. Right now the select statements are repeated.

Now the time has come that I need to add anoter dependent criteria. I don't want to have 4 different cases where the property conditions are slightly different.

What I want to do, is something like this:

Func<Fruit, bool> fruitFunc = f => false;

if(userLikesBananas)
{
    fruitFunc = f => Bowl.Any(b => b.OwnedBy == user && b.Contains(f) && f.Type == FruitType.Banana);
}
else
{
    fruitFunc = f => Bowl.Any(b => b.Contains(f));
}

return from fruit in basket
       select new Fruit
       {
           AteBanana = fruitFunc(fruit)
           ...
           ...
           //lots of properties
           ...
       };

The trouble is that is the expression cannot be converted to sql, as it contains a dynamic invoke. I have tried wrapping the Func in an Expression, but the same problem seems to arise.

So the question is, how can I avoid the copy and paste?

A: 

Hope this will help you to achieve task you want : Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library) alt text

Pranay Rana
I did think of this, but I'd rather not lose the type safety by passing strings around. I really don't see this as a dynamic query as such, just a way of changing the expression before its translated.
SteadyEddi
A: 

I can suggest writing the Func in a different way (maybe something like this):

fruitFunc = f => Bowl.Any(b => ((f.Type == FruitType.Banana && b.OwnedBy == user && userLikesBananas) || !userLikesBananas) && b.Contains(f));

I haven't tested if it works but this may be a way to write the function to cover more cases (not only 2). The approach is somehow similar to boolean algebra as I remember...

Cheers...

Padel
This approach will mean that the whole expression will be converted to sql, `userLikesBananas` will be passed in. I am looking for a way that means the expression is adjusted before it is translated to sql. Using an if statement will result in a cleaner query, but its a nice idea, thanks.
SteadyEddi
A: 

Try to rewrite subquery (select(....Any..Any...) to join clause. Then:

var query = (from user in entity.User.Include("Department")  select user);

    if (!String.IsNullOrEmpty(filter.Login))
    {
        query = query.Where(a => a.Login.Contains(filter.Login));
    }

    if (!String.IsNullOrEmpty(filter.LastName))
    {
        query = query.Where(a => a.LastName.Contains(filter.LastName));
    }

    if (!String.IsNullOrEmpty(filter.Email))
    {
        query = query.Where(a => a.Email.Contains(filter.Email));
    }
igor
a where filter can be achieved like this... but a select projection cannot.
SteadyEddi
Try to rewrite subquery (select(....Any..Any...) to join clause.
igor