Создайте лямбда-дерево выражений с определенным полем в связанной сущности - PullRequest
1 голос
/ 27 сентября 2019

МОДЕЛЬ ДАННЫХ

public class TABLE
    {
        [Key]
        public int ID { get; set; }
        public int ONEFIELD { get; set; }

        // -------------------- ForeignKey --------------------
        [ForeignKey("People")]
        public long PeopleID { get; set; }
        public virtual People People { get; set; }
    }

    public class People
    {
        [Key]
        public long PeopleID { get; set; }
        public int CountryID { get; set; }
    }

Мне нужно построить лямбду, чтобы запросить эту МОДЕЛЬ:

Получить TABLE.ONEFIELD = 1 И TABLE.PEOPLE.COUNTRYID = 6

LINQ-эквивалент

_context.TABLEs
  .Where(e => e.ONEFIELD == 1)
  .Include(e => e.People)
  .Where(i=>i.People.CountryID == 6);

Моя попытка

  public static Expression<Func<TEntity, bool>> BuildLambda<TEntity>(OBJTYPE obj)
        {

        var item = Expression.Parameter(typeof(TEntity), "table");
        Expression query = null;


        // 1
        var prop1 = Expression.Property(item, "ONEFIELD");
        var value1 = Expression.Constant(1);
        var equal1 = Expression.Equal(prop1, value1);
        var lambdaFIELDONE = Expression.Lambda<Func<TEntity, bool>>(equal1, item);
        query = lambdaFIELDONE.Body;

        // 2
        var prop2 = Expression.Property(item, typeof(People).Name + ".CountryID");
        var value2 = Expression.Constant(6);
        var equal2 = Expression.Equal(prop2, value2);
        var lambdaCOUNTRYID = Expression.Lambda<Func<TEntity, bool>>(equal2, item);
        query = Expression.And(query, lambdaCOUNTRYID);

    }

, но я получаю эту ошибку

System.ArgumentException: свойство Instance 'People.CountryID 'не определен для типа' SOLUTION.Models.TABLE '

Мне не нужен Generic, только фиксированная лямбда (и я не мог использовать LINQ).

Я пробовал несколько вещей, чтобы поймать People.CountryID вроде

Expression.Property(item1, typeof(People).GetProperty("CountryID"));
Expression.Property(item, typeof(People).Name+"." + typeof(People).GetProperty("CountryID"));
Expression.Property(item, typeof(People).Name + "." + typeof(People).GetProperties().Where(x => x.Name == "CountryID").FirstOrDefault().Name);

безуспешно

Есть идеи?спасибо

1 Ответ

1 голос
/ 28 сентября 2019

Таким образом, чтобы создать вложенный доступ к свойству, вы должны вложить Expression s, которые получают доступ к каждому уровню.Затем вы можете объединить тесты в тело и, наконец, создать лямбду для результата:

public static Expression<Func<TEntity, bool>> BuildLambda<TEntity>(OBJTYPE obj) {
    // (TEntity table)
    var parmTable = Expression.Parameter(typeof(TEntity), "table");

    // table.ONEFIELD
    var prop1 = Expression.Property(parmTable, "ONEFIELD");
    // table.ONEFIELD == 1
    var equal1 = Expression.Equal(prop1, Expression.Constant(1));

    // table.People
    var prop2_1 = Expression.Property(parmTable, nameof(People));
    // table.People.CountryID
    var prop2_2 = Expression.Property(prop2_1, "CountryID");
    // table.People.CountryID == 6
    var equal2 = Expression.Equal(prop2_2, Expression.Constant(6));

    // table.ONEFIELD == 1 && table.People.CountryID == 6
    var finalBody = Expression.AndAlso(equal1, equal2);

    // table => table.ONEFIELD == 1 && table.People.CountryID == 6
    return Expression.Lambda<Func<TEntity, bool>>(finalBody, parmTable);
}

Используя LINQPad, вы можете создать образец лямбды и затем использовать метод Dump, и вы увидите, чтоnested FieldExpression создан, что и создается при вызове Expression.Property:

Expression<Func<TEntity, int>> f = t => t.People.CountryID;

f.Dump();
...