如何在Linq where子句中指定动态字段名称?

如果您创建一个Filter对象,其中包含Linq的条件,通常在where子句中,如下所示:

var myFilterObject = FilterFactory.GetBlank(); myFilterObject.AddCondition("Salary", "lessThan", "40000"); var myResult = myRepository.GetEmployees(myFilterObject); 

如何在不使用大案例声明的情况下将Linq字段与字段名称匹配?

  return from e in db.Employee where e.Salary < 40000 select new IList { Name= e.name, Salary= e.Salary }; 

我假设您需要将一个对象发送到指定过滤的存储库,以便您只提取所需的记录。 我假设Linq没有预编译(除非您创建自定义委托和函数),因此您应该能够动态指定要筛选的字段。

如果你可以像某些类型的Expando对象那样做e [“Salary”]这样的话会很好。

我建议您查看Linq to SQL示例中的Dynamic Query 。 您可以使用它以“纯文本”编写条件,例如:

 var employees = db.Employee.Where("Salary < 40000").Select(...); 

澄清一下:这些扩展本质上构建了通常通过lambdas构造的字符串中的相同表达式树,因此这与针对数据库编写原始SQL不同。 唯一的缺点是你不能使用查询理解语法( from x in y等)。

您可以手动构建表达式,如下所示:

 var eParam = Expression.Parameter(typeof(Employee), "e"); var comparison = Expression.Lambda( Expression.LessThan( Expression.Property(eParam, "Salary"), Expression.Constant(40000)), eParam); return from e in db.Employee.Where(comparison) select new EmployeeViewModel { Name = e.name, Salary = e.Salary }; 

我知道,我已经迟到了这个派对 – 但是我已经编写了一些我认为不使用DynamicLINQ来满足这个要求的代码,我发现它支持得很差,并且使用起来很狡猾(充其量)。

  ///  /// A method to create an expression dynamically given a generic entity, and a propertyName, operator and value. ///  ///  /// The class to create the expression for. Most commonly an entity framework entity that is used /// for a DbSet. ///  /// The string value of the property. /// An enumeration type with all the possible operations we want to support. /// A string representation of the value. /// The underlying type of the value /// An expression that can be used for querying data sets private static Expression> CreateDynamicExpression(string propertyName, Operator op, string value, Type valueType) { Type type = typeof(TEntity); object asType = AsType(value, valueType); var p = Expression.Parameter(type, "x"); var property = Expression.Property(p, propertyName); MethodInfo method; Expression q; switch (op) { case Operator.Gt: q = Expression.GreaterThan(property, Expression.Constant(asType)); break; case Operator.Lt: q = Expression.LessThan(property, Expression.Constant(asType)); break; case Operator.Eq: q = Expression.Equal(property, Expression.Constant(asType)); break; case Operator.Le: q = Expression.LessThanOrEqual(property, Expression.Constant(asType)); break; case Operator.Ge: q = Expression.GreaterThanOrEqual(property, Expression.Constant(asType)); break; case Operator.Ne: q = Expression.NotEqual(property, Expression.Constant(asType)); break; case Operator.Contains: method = typeof(string).GetMethod("Contains", new[] {typeof(string)}); q = Expression.Call(property, method ?? throw new InvalidOperationException(), Expression.Constant(asType, typeof(string))); break; case Operator.StartsWith: method = typeof(string).GetMethod("StartsWith", new[] {typeof(string)}); q = Expression.Call(property, method ?? throw new InvalidOperationException(), Expression.Constant(asType, typeof(string))); break; case Operator.EndsWith: method = typeof(string).GetMethod("EndsWith", new[] {typeof(string)}); q = Expression.Call(property, method ?? throw new InvalidOperationException(), Expression.Constant(asType, typeof(string))); break; default: throw new ArgumentOutOfRangeException(nameof(op), op, null); } return Expression.Lambda>(q, p); } ///  /// Extract this string value as the passed in object type ///  /// The value, as a string /// The desired type /// The value, as the specified type private static object AsType(string value, Type type) { //TODO: This method needs to be expanded to include all appropriate use cases string v = value; if (value.StartsWith("'") && value.EndsWith("'")) v = value.Substring(1, value.Length - 2); if (type == typeof(string)) return v; if (type == typeof(DateTime)) return DateTime.Parse(v); if (type == typeof(DateTime?)) return DateTime.Parse(v); if (type == typeof(int)) return int.Parse(v); if (type == typeof(int?)) return int.Parse(v); throw new ArgumentException("A filter was attempted for a field with value '" + value + "' and type '" + type + "' however this type is not currently supported"); } 

这段代码可以这样使用:

 var whereClause = CreateDynamicExpression("MyFieldName", Operator.Contains, "some string value",typeof(string)); var results = _db.MyDatabaseTable.Where(whereClause);