I am looking to implement a system whereby a use that 'build' conditions and then return the resulting data back from the database. At present, there is a stored procedure which generates SQL on the fly and executes it. This is a particular issue that I want to remove.
My problem is coming from the fact that I can have multiple fields within my criteria, and for each of these fields, there could be 1 or more values, with different potential operators.
For example,
from t in Contacts
where t.Email == "[email protected]" || t.Email.Contains ("mydomain")
where t.Field1 == "valuewewant"
where t.Field2 != "valuewedontwant"
select t
The field, criteria and operator are stored in the database (and List<FieldCriteria>) and would be some thing like this (based on above);
Email, Equals, "[email protected]"
Email, Contains, "mydomain" Field1,
Equals, "valuewewant" Field2,
DoesNotEqual, "valuewedontwant"
or
new FieldCriteria
{
FieldName = "Email",
Operator = 1,
Value = "[email protected]"
}
So using the information that I have, I want to be able to build a query with any number of conditions. I have seen previous links to Dynamic Linq and PredicateBuilder, but am not able to visualise this as a solution to my own problem.
Any suggestions would be appreciated.
Update
Following on from the suggestion about Dynamic Linq, I came up with a very basic solution, using a Single Operator, with 2 Fields and multiple Criteria. A little crude at the moment as coded in LinqPad, but the results are exactly what I wanted;
enum Operator
{
Equals = 1,
}
class Condition
{
public string Field { get; set; }
public Operator Operator { get; set;}
public string Value { get; set;}
}
void Main()
{
var conditions = new List<Condition>();
conditions.Add(new Condition {
Field = "Email",
Operator = Operator.Equals,
Value = "[email protected]"
});
conditions.Add(new Condition {
Field = "Email",
Operator = Operator.Equals,
Value = "[email protected]"
});
conditions.Add(new Condition {
Field = "Field1",
Operator = Operator.Equals,
Value = "Chris"
});
var statusConditions = "Status = 1";
var emailConditions = from c in conditions where c.Field == "Email" select c;
var field1Conditions = from c in conditions where c.Field == "Field1" select c;
var emailConditionsFormatted = from c in emailConditions select string.Format("Email=\"{0}\"", c.Value);
var field1ConditionsFormatted = from c in field1Conditions select string.Format("Field1=\"{0}\"", c.Value);
string[] conditionsArray = emailConditionsFormatted.ToArray();
var emailConditionsJoined = string.Join("||", conditionsArray);
Console.WriteLine(String.Format("Formatted Condition For Email: {0}",emailConditionsJoined));
conditionsArray = field1ConditionsFormatted.ToArray();
var field1ConditionsJoined = string.Join("||", conditionsArray);
Console.WriteLine(String.Format("Formatted Condition For Field1: {0}",field1ConditionsJoined));
IQueryable results = ContactView.Where(statusConditions);
if (emailConditions != null)
{
results = results.Where(emailConditionsJoined);
}
if (field1Conditions != null)
{
results = results.Where(field1ConditionsJoined);
}
results = results.Select("id");
foreach (int id in results)
{
Console.WriteLine(id.ToString());
}
}
With an SQL generated of;
-- Region Parameters
DECLARE @p0 VarChar(1000) = 'Chris'
DECLARE @p1 VarChar(1000) = '[email protected]'
DECLARE @p2 VarChar(1000) = '[email protected]'
DECLARE @p3 Int = 1
-- EndRegion
SELECT [t0].[id]
FROM [Contacts].[ContactView] AS [t0]
WHERE ([t0].[field1] = @p0) AND (([t0].[email] = @p1) OR ([t0].[email] = @p2)) AND ([t0].[status] = @p3)
And Console Output:
Formatted Condition For Email: Email="[email protected]"||Email="[email protected]"
Formatted Condition For Field1: Field1="Chris"
Just need clean this up and add the other Operators and it is looking good.
If anyone has any comments on this so far, any input would be appreciated