How to dynamically construct / modify part of a LINQ statement
I have a method in my application that needs to read, filter and serve data based on a set of criteria. I am trying to use LINQ to accomplish this:
var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
&& (!string.IsNullOrEmpty(data.PlatformTcv) && data.PlatformTcv != "#N/A")
select data;
By itself, this works great. The problem is that depending on the search criteria and not data.PlatformTvc it could be data.WorkspaceTvc or data.CyberTvc etc. I have no way of knowing in advance which of the 5 possible options needs to be evaluated.
My question is, is there a way to construct a LINQ statement in such a way that part of the statement is conditionally executed. So if the user passes "Platform" as search criteria, the LINQ operator will read ... string.IsNullOrEmpty(data.PlatformTcv)
, but if the criteria is "Cyber", then this LINQ operator should read ... string.IsNullOrEmpty(data.CyberTcv)
Is there a way to do this?
source to share
Sure. Take advantage of the LINQs lazy execution model and insert a plugin variable into your query. For example:
Func<DataObject, string> accessor = data => data.PlatformTcv;
var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
&& (!string.IsNullOrEmpty(accessor(data))
&& accessor(data) != "#N/A")
select data;
var basedOnPlatform = pipelineData.ToArray();
accessor = data => data.CyberTV;
var basedOnCyber = pipelineData.ToArray();
(This assumes that the type of the query element is DataObject
. Of course, you would replace this with the actual name of the type you are using.)
Just remember that this will make LINQ more difficult to understand and always respect the nature of your queries. That is, if they are not "materialized" like some other collection (for example, they are called ToArray()
), then the changes in the underlying query will be reflected the next time it is executed.
source to share
You can create an IQueryable for a part that will be the same for all queries:
var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won");
// etc
Then apply a custom filter:
if (somecondition)
{
pipelineData = pipelineData.Where(x => x.SomeField == "somevalue");
}
// etc
source to share