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?
…my english is not good, but I’ll try to explain how to easily solve this problem 🙂
Dynamic Linq is bad for type control – It’s easy to use, but you can’t browse the resulting object (x.Name, x.Surname, etc.)
There is (a litle noob-like) trick to solve this problem (I’m using it and its working fain):
Create
enumwith attributes of your object you’re selecting from.public enum MyAtrs{ID, FirstName, Surname}
create
Dictionary<MyAtrs,bool>(and fill it) for conditions (settrueif you want to get this property)public Dictionary Dic = new Dictionary();
Dic.Add(MyAtrs.ID,true);
Dic.Add(MyAtrs.Firstname,false);
Dic.Add(MyAtrs.Surname,true);
Built your query:
var query = DBContext.MyDBTable.Where(predicate).Select(e=>new {
ID = Dic[MyAtrs.ID] ? e.dbID:0,
Firstname = Dic[MyAtrs.Firstname] ? e.dbFirstname:null,
Surname = Dic[MyAtrs.Surname] ? e.dbSurname:null,
});
In this case, there will be all 3 columns in the SQL Select statement, but it’s just a few bytes (who matters…). SQL Server gives you back all 3 columns but (in this case) Firstname will be empty (something like {ID=123, Firstname=, Surname=”Jobs”}).
It’s not brilliant but it’s easy way how to built “dynamic” select expression without loosing type control 🙂