Reputation: 44295
We have an object
public class SomeObject
{
public Name {get;set;}
public City {get;set;}
public State {get;set}
//various other parameters. Let's say there's ~20
}
Is it possible to dynamically create new LINQ queries without recompilation of source code? Instead, the query parameters come from an XML structure that is stored and updated in the database.
var result = from i in someObj
where
//XML requests Name = 'Bob'...so append this where clause
name = 'Bob'
Can this be done?
Upvotes: 47
Views: 125338
Reputation: 1093
Maybe Dynamic Linq can help you: Dynamic linq part 1: Using the linq dynamic query library
query = query.Where("Id = 123 And Age > 18");
Or you can manipulate your Linq query directly:
query = query.Where(x=>x.Id == 5);
Upvotes: 9
Reputation: 6719
Here is a solution with expression trees:
var param = Expression.Parameter(typeof(SomeObject), "p");
var exp = Expression.Lambda<Func<SomeObject, bool>>(
Expression.Equal(
Expression.Property(param, "Name"),
Expression.Constant("Bob")
),
param
);
var query = someObj.Where(exp);
I know it's much more complex, but this may be useful in times.
Upvotes: 151
Reputation: 22260
It's hard for me to tell based on your question, but in some cases you don't need dynamic Linq and can simply do this...
var result = from o in someObj
where (Name == null || o.Name == Name)
&& (City == null || o.City == City)
&& (State == null || o.State == State)
select o;
This will essentially prevent the data from being filtered when the parameter in question is null. And it still performs well thanks to the short-circuiting behavior in C#.
Upvotes: 36
Reputation: 67135
I believe you will have to actually dig into Expression Trees. I have not dug very far into this, so I cannot create a sample for you, but I do know that you can use Expression Trees to dynamically build your queries and then call .Compile (in the code) to have it runnable.
Actually, here is a better link Building Dynamic Queries with Expression Trees. It should give you exactly what you want, and is fairly succinct for what it is. This should act as a good example for you :)
Upvotes: 9
Reputation: 156748
Yes, it's actually pretty easy:
var name = GetBobNameFromXml();
var result = someObj.Where(i => i.Name == name);
You can also choose whether or not to apply criteria piecemeal.
var result = someObj;
var name = xmlCriteria.Name;
if(!string.IsNullOrEmpty(name))
{
result = result.Where(i => i.Name == name);
}
// follow the same pattern for city, state, etc.
You could even use a pattern that uses a name-keyed dictionary of criterion funcs, to avoid a bunch of if
statements.
foreach(var criterionPair in xmlCriteria)
{
var value = criterionPair.Value;
result = result.Where(i => propGetters[criterionPair.PropertyName](i, value));
}
Basically, there's a lot you can do along these lines. If you want an answer more specifically tailored to your situation, you'll need to provide a more specific question.
Upvotes: 5
Reputation: 181087
You'll most certainly want to take a look at Dynamic Linq which will allow you to define the query conditions as text.
As for adding conditions dynamically, you can add conditions to a query using similar syntax to;
if(CategoryIsImportant)
myQuery = myQuery.Where("CategoryId=2");
all of which you can (fairly easily) encode into an XML format of your choice.
Upvotes: 30
Reputation: 54927
I assume you want to introduce optional filters, depending on the content of your XML. To continue on the example by StriplingWarrior:
var name = GetNameFromXml();
var city = GetCityFromXml();
var state = GetStateFromXml();
var result = someObj;
if (name != null)
result = result.Where(i => i.Name == name);
if (city != null)
result = result.Where(i => i.City == city);
if (state != null)
result = result.Where(i => i.State == state);
This way, you would be applying any number of filters (from none to all three), depending on what is actually specified in your XML.
Upvotes: 5