Как применить дерево выражений к объекту с нулевыми параметрами

#c# #entity-framework #linq #expression

#c# #entity-framework #linq #выражение

Вопрос:

У меня есть этот объект

 public class Ledger
{
   public string fund {get;set;}
   public string location {get;set;}
   public string costCenter {get;set;}
   public string objects {get;set;}
}
  

Я использую эти параметры фильтра, которые означают, что каждое из этих значений может быть null или может быть fill. В SQL запрос будет выглядеть следующим образом

 SELECT FROM GlAccts WHERE fund = "10" AND location = "1" AND objects = "45"
SELECT FROM GlAccts WHERE objects = "45"
SELECT FROM GlAccts WHERE location = "1" AND objects = "45"
  

Я пытаюсь преобразовать это в linq, я наткнулся на дерево выражений, которое звучит многообещающе, но у меня есть несколько проблем,

  1. Как я могу вернуть список значений с помощью дерева выражений
  2. Как я могу объединить выражение с И когда у меня есть выражение, которое равно null.

На данный момент это то, что у меня есть.

 // filtersObject, is my object which would contains fund,location,costCenter,object, just to note it is currently in a foreach (var filtersObjects) since I plan to have multiple filter objects but i am not worry about this section.
// my active list right now is List<glUserAccess> but I dont know where to apply this


            ParameterExpression pe = Expression.Parameter(typeof(GlAccts), "glAccts");

            Expression e1 = null;
            Expression e2 = null;
            Expression e3 = null;
            Expression e4 = null;

            // Fund EQ ""
            if (!string.IsNullOrEmpty(filtersObject.fund)) {
                Expression left = Expression.Property(pe, typeof(string).GetProperty("fund")); ;
                Expression right = Expression.Constant(filtersObject.fund, typeof(string));
                e1 = Expression.Equal(left, right);
            }

            // Location EQ ""
            if (!string.IsNullOrEmpty(filtersObject.location)) {
                Expression left = Expression.Property(pe, typeof(string).GetProperty("location")); ;
                Expression right = Expression.Constant(filtersObject.location, typeof(string));
                e2 = Expression.Equal(left, right);
            }

            // Cost Center EQ ""
            if (!string.IsNullOrEmpty(filtersObject.costCenter)) {
                Expression left = Expression.Property(pe, typeof(string).GetProperty("costCenter")); ;
                Expression right = Expression.Constant(filtersObject.costCenter, typeof(string));
                e3 = Expression.Equal(left, right);
            }

            // Objects EQ ""
            if (!string.IsNullOrEmpty(filtersObject.objects)) {
                Expression left = Expression.Property(pe, typeof(string).GetProperty("objects")); ;
                Expression right = Expression.Constant(filtersObject.objects, typeof(string));
                e4 = Expression.Equal(left, right);
            }

            var e1e2 = Expression.AndAlso(e1,e2);
            var e1e2e3 = Expression.AndAlso(e1e2, e3);
            var e1e2e3e4 = Expression.AndAlso(e1e2e3, e4);

            var ExpressionTree = Expression.Lambda<Func<GlAccts, bool>>(e1e2e3e4, new[] { pe });
  

Ответ №1:

Вы можете комбинировать свои вложенные выражения с AndAlso . Следующий код использует отражение, чтобы получить все свойства из Ledger и создать динамическое лямбда-выражение:

 public static Expression<Func<T, bool>> CreateExpression<T>(Ledger ledger)
{
    var parameter = Expression.Parameter(typeof(T), "x");

    Expression body = null;
    foreach (var property in ledger.GetType().GetProperties())
    {
        var value = property.GetValue(ledger);
        if (value == null)
            continue;

        var equals = Expression.Equal(
            Expression.Property(parameter, property.Name),
            Expression.Constant(value));

        body = body == null ? equals : Expression.AndAlso(body, equals);
    }

    if (body == null) // no filters
        body = Expression.Constant(true);

    var lambda = Expression.Lambda<Func<T, bool>>(body, parameter);
    return lambda;
}
  

В случае, когда все свойства в книге имеют значение null, он вернет x => true , что lambda ничего не будет фильтровать