I have a list of objects in a hierarchical structure. I want to build complex LINQ queries against that object list based on "conditions" a client company sets and are stored in the database. So I need to build these at run time, but because they will be run repeatedly whenever the client's users update or refresh their data I would like to store the LINQ queries in objects rather than rebuild them each time.
I have looked at ScottGu's Blog about Dynamic LINQ.
Also this article about using expression trees.
Neither of these appear to provide an adequate solution, but I may not be understanding them adequately. I'm afraid that I'm trying to use LINQ when I should consider other options.
My object hierarchy:
WorkOrder[]
Field[]
Task[]
Field[]
Here is an example of a LINQ query that I would like to store and execute. I can reasonably build this format based on the database records that define the conditions.
var query =
from wo in WorkOrders
from woF in wo.Fields
from task in wo.Tasks
from taskF in task.Fields
from taskF2 in task.Fields
where woF.Name == "System Status"
&& woF.Value.Contains("SETC")
&& taskF.Name == "Material"
&& taskF.Value == "Y"
&& taskF2.Name == "Planner"
&& taskF2.Value == "GR5259"
select new
{
wo_id = wo.ID,
task_id = task.ID
};
A few considerations.
In my code I envision:
//1) Retrieve business rules from DB. I can do this.
//2) Iterate through the business rules to build the linq queries.
foreach (BusinessRule br in BusinessRules) {
//Grab the criteria for the rule from the DB.
//Create a linq to object query based on the criteria just built.
//Add this query to a list for later use.
}
...Elsewhere in application.
//Iterate through and execute the linq queries in order to apply business rules to data cached in the application.
foreach (LinqQuery q in LinqQueries) {
//Execute the query
//Apply business rule to the results.
}
Thank you very much for your thoughts, effort and ideas.
Based on the discussion with Guillaume I would only suggest to pay attention to the type of the resulting query when playing around with advanced dynamic query generation. If you are changing the shape of what is being returned via Select
, Aggregate
, or one of the other methods you will expect your inner type to change accordingly. If you are just filtering with Where you can keep adding on as many additional cases you want unless you want OR behavior then things like PredicateBuilder helps. If you want to pull in more data via Join
, Zip
, ... then you are either doing so to filter, add to the rows returned, and possibly change the shape of the data.
I've done a lot of this in the past and had most success focusing on specific helper methods that allow for common cases that I need and then leaning on linq expression trees and patterns such as the visitor pattern to allow custom expression built at runtime.