Я имею дело с scanario типов Nullable во время формирования динамических выражений запроса. Эти выражения будут извлекать отфильтрованные данные из любых таблиц SQL (взаимодействующих с классами First Code с использованием EF).Как получить выражение для Nullable значений (полей) без преобразования из Expression.Convert в C#?
У меня нормальный объект (например, Консигнация работает с несколькими свойствами наряду с свойствами Nullable).
Мое формирование выражения идет хорошо до тех пор, пока я не встречу некоторые типы Nullable. На этих nullables, я получаю
Бинарный оператор NotEqual не определен для 'System.Nullable`1 [System.Single]' типов и 'System.Single'.
Для устранения этого исключения, я использую все оценки относительно конвертации, размещенные на разных потоках.
Invoking lambda expressions in Expression trees
Trying to filter on a Nullable type using Expression Trees
Это все порождающих выражения с добавлением слова "Преобразовать" (то есть конвертировать (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();
}
}
Что вы хотите, если значение равно null? И что * точно * вы подразумеваете под «не будет получать данные из таблиц»? Что представляет собой сгенерированный SQL, и для чего вам это нужно? –
Jon Skeet: Конечно, если значение равно null, то это будет просто пропущено. У меня есть пользовательский интерфейс, где пользователи вводят свои фильтры вручную. Эти фильтры затем преобразуются для формирования выражений. Затем эти выражения применяются к огромному набору данных для получения фильтрованных записей. Итак, в моем случае ther не будет фильтром, который вообще может содержать обнуляемый vlaue. Но таблица данных, отображаемая с помощью кода, сначала работающего с полями с нулевым значением – Usman
Я ничего не вижу «конечно» об этом ... существуют определенные варианты, которые могут быть одинаково действительными. Но похоже, что вы хотите »(t.Consignment.Weight.HasValue && t.Consignment.Weight.Value! = 5000)' или что-то в этом роде. Другими словами, вы можете использовать свойства «HasValue» и «Value» для укажите * точно *, что вы хотите. –