I am looking to implement a system that uses the condition "build", and then return the received data from the database. There is currently a stored procedure that generates SQL on the fly and executes it. This is a special problem that I want to remove.
My problem comes from the fact that I can have several fields within my criteria, and for each of these fields there can be 1 or more values with different potential operators.
For example,
from t in Contacts where t.Email == " email@domain.com " || 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 will be like this (based on above);
Email, Equals, " email@domain.com " Email, Contains, "mydomain" Field1, Equals, "valuewewant" Field2, DoesNotEqual, "valuewedontwant"
or
new FieldCriteria { FieldName = "Email", Operator = 1, Value = " email@mydomain.com " }
Therefore, using the information that I have, I want to be able to create a request with any number of conditions. I have seen previous links to Dynamic Linq and PredicateBuilder, but cannot imagine this as a solution to my own problem.
Any suggestions would be appreciated.
Update
Following Dynamic Linq's suggestion, I came up with a very simple solution using a Single Operator, with two fields and several criteria. A bit rude at the moment, as encoded 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 = " email1@domain.com " }); conditions.Add(new Condition { Field = "Email", Operator = Operator.Equals, Value = " email2@domain.com " }); 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 SQL generated from
-- Region Parameters DECLARE @p0 VarChar(1000) = 'Chris' DECLARE @p1 VarChar(1000) = ' email1@domain.com ' DECLARE @p2 VarChar(1000) = ' email2@domain.com ' 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=" email1@domain.com "||Email=" email2@domain.com " Formatted Condition For Field1: Field1="Chris"
You just need to clear this and add other Operators, and it looks good.
If anyone has comments on this, any input would be appreciated