问题
I have user-interface where user can select grid column (like age) and operator (lesser than, equals or greater than) for that column.
Grid data is then filtered according to the selection.
I have a following classes that are deserialized from the JSON that is coming from the client.
/// <summary>
/// Filter for reducing grid results
/// </summary>
public class Filter
{
/// <summary>
/// Name of the column
/// </summary>
public string name;
public string value;
public int @operator { private get; set; }
public Operator Operator()
{
return (Operator) @operator;
}
}
public enum Operator
{
None = -1,
LesserThan = 0,
Equals = 1,
GreaterThan = 2
}
Due to the nature dynamically adding new columns for filtering I would like to create generic solution for accessing the data.
I would like avoid having huge amount if/switch statements like
switch(columnName)
{
case "age":
{
if(operator == Operator.LesserThan)
{
query = entities.Where(o => o.Age < age);
}
else if (operator == Operator.GreaterThan)
{
query = entities.Where(o => o.Age > age);
}
etc.
break;
}
etc.
}
Any ideas how to create more generic solution for the problem?
Update It seems that there many ways to accomplish cleaner solution than one billion if statements. Now I just need to compare different solutions.
回答1:
You could use Dynamic LINQ to create the query dynamically
Edit:
An example for Dynamic LINQ query would look like this, assuming that the column names in the grid are the same as the field names in the entity:
string queryString;
queryString = columnName;
if(operator == Operator.LesserThan)
{
queryString += " < ";
}
else if (operator == Operator.GreaterThan)
{
queryString += " > ";
}
etc.
queryString += age.ToString(); // Or use bind variables, haven't tried that myself in dynamic LINQ
query = entites.Where(queryString);
回答2:
You can use the PredicateBuilder to dynamically build up linq queries based on whatever youi want. That will help you build up a linq expression easily. As for the ugly switch that would grow and grow over time, I would suggest perhaps if "name" always related to a property in your linq expression (e.g. "age" --> .Age), then you should be able to get that with some reflection code - so you check if "name" does relate to a property of the same name, and if so build a filter for it..
HTH
回答3:
You can pass to the Where method a System.Linq.Expressions.Expression object that you compose from your input. Here is an example of how to compose predicate expressions for use with EF or Linq2Sql: Dynamically Composing Expression Predicates
回答4:
You can use ESQL instead of just LINQ:
Context.Entities
.Where("it.Age > @Age", new[] { new ObjectParameter("Age", age } );
you can easily generate string representation for your criteria based on the filter you have.
Here is the full reference to ESQL should you need it.
回答5:
You can use reflection code such as :
String columName; //your dynamic columnName
if(operator == Operator.LesserThan)
{
query = entities.Where(o => o.GetType().GetProperty(columName).GetValue(o, null) <columName);
}
else if (operator == Operator.GreaterThan)
{
etc.
}
来源:https://stackoverflow.com/questions/9189986/generating-linqtoentities-where-statement-depending-on-the-user-selection