【发布时间】:2015-02-12 09:29:26
【问题描述】:
我在动态查询表达式的形成过程中处理 Nullable 类型的扫描。这些表达式将从任何 SQL 表中获取过滤后的数据(使用 EF 与 Code First 类交互)。
我有正常的对象(例如,在多个属性上运行的寄售以及可为空的属性)。
在遇到一些 Nullable 类型之前,我的表达式形成很顺利。在这些可空值上,我得到了
没有为“System.Nullable`1[System.Single]”和“System.Single”类型定义二元运算符 NotEqual。
为了消除此异常,我使用了所有关于在不同线程上发布的转换的方法。
Invoking lambda expressions in Expression trees
Trying to filter on a Nullable type using Expression Trees
这些都是生成带有添加单词“Convert”(即 Convert(someValue) )的表达式,结果我总是有表达式
t=>(t.Consignment.Id = 45000 && t.Consignment.someProperty>=45 Or t.Consignment.Weight! = Convert(5000)).
当然,我需要上面的整个表达式,而不需要“转换”。因为这个“转换”不会相应地从表中获取数据。
任何帮助将不胜感激!还应该做什么?我已经知道转换,但这会使整个表达式无用,因为由于不必要的“转换”,它不会投影记录
已添加
Expression NotEqual<T>(Expression PropertyType, ConstantExpression a_Constant, ParameterExpression parameter)
{
if(IsNullableType(Property.Type) &&!IsNullableType(a_Constant.Type))
{
var converted = a_Constant.Type != Property.Type ? (Expression)Expression.Convert(a_Constant, Property.Type): (Expression)a_Constant;
// here above statement returns (Convert(50000)) and all I want (50000), but i tried all combinitions from Expression in order to form this constant as expression, it always throws exception what I mentioned originally.
var body = Expression.MakeBinary(ExpressionType.NotEqual, PropertyType, converted);
//MakeBinary statement returns {(t.Weight != Convert(5000000))} but I need {(t.Weight != 5000000)}
var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
return expr;
}
}
代码:
public class Consignment
{
public float? Weight { get; set; }
}
public static class GenericQueryExpressionBuilder
{
private static Expression NotEqual<T>(Expression memberExpression, ConstantExpression a_Constant, ParameterExpression parameter)
{
ConstantExpression constantExpression = null;
if (IsNullableType(memberExpression.Type) && !IsNullableType(a_Constant.Type))
{
//var converted = a_Constant.Type != memberExpression.Type ? (Expression)Expression.Convert(a_Constant, memberExpression.Type) : (Expression)a_Constant;
Expression constantExp = Expression.Property(a_Constant,typeof(T),"Weight");
**// above statement throws exception I commented.**
var body = Expression.MakeBinary(ExpressionType.NotEqual, memberExpression, converted);
//here I want "t=>(t.Weight!=5000.0) INSTEAD of t=>(t.Weight!=Convert(5000.0))"
var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
return expr;
}
else if (!IsNullableType(memberExpression.Type) && IsNullableType(a_Constant.Type))
memberExpression = Expression.Convert(memberExpression, a_Constant.Type);
return Expression.NotEqual(memberExpression, constantExpression);
}
static bool IsNullableType(Type t)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
private static Expression GetExpression<T>(ParameterExpression param, string a_strPropertyName, string Operator, object Value)
{
MemberExpression member = Expression.Property(param, a_strPropertyName);
ConstantExpression constant = Expression.Constant(Value);
try
{
return GenericQueryExpressionBuilder.NotEqual<T>(member, constant, param);
}
catch (InvalidOperationException)
{
return null;
}
return null;
}
public static Expression<Func<T, bool>> GetExpression<T>(Consignment consignment)
{
Expression expression = null;
var parameter = Expression.Parameter(typeof(T), "t");
string PropertyName = "Weight";
string Operation = "NotEqual";
object Value = consignment.Weight;
expression = GenericQueryExpressionBuilder.GetExpression<T>(parameter, PropertyName, Operation, Value);
return Expression.Lambda<Func<T, bool>>(expression, parameter);
}
}
class Program
{
static void Main(string[] args)
{
Consignment consignment = new Consignment();
consignment.Weight = 50000.0f;
var deleg = GenericQueryExpressionBuilder.GetExpression<Consignment>(consignment).Compile();
}
}
【问题讨论】:
-
如果值为空,你想发生什么? “不会相应地从表中获取数据”是什么确切?生成的 SQL 是什么样的,您需要它是什么样的?
-
Jon Skeet :当然,如果值为空,那么它会被简单地跳过。我有一个用户界面,用户可以在其中手动输入过滤器。然后将这些过滤器转换为表达式。然后将这些表达式应用于庞大的数据集以获取过滤记录。因此,就我而言,根本没有过滤器可以包含可为空的值。但是通过代码映射的数据表首先对可空字段进行操作
-
我没有看到任何“当然”的东西......肯定还有其他同样有效的选择。但听起来你想要 "(t.Consignment.Weight.HasValue && t.Consignment.Weight.Value != 5000)` 或类似的东西。换句话说,你可以使用
HasValue和Value属性来指定准确你想要什么。 -
对! ,这就是我想要的。但是如何构建可以与其他表达式进一步连接的表达式。 If(IsNullable(constantExpression)) { Expression.(property,constantExpression.Value) }... 但这会产生相同的措辞,我发布了问题。
-
恐怕我现在没有关注你。如果您能提供一个简短但完整的程序来演示问题,那么对您的帮助会容易得多。
标签: c# lambda expression-trees linq-expressions