Как передать LambdaExpression в IncludeFilter?


Вопрос

Я пытаюсь передать динамически генерируемое выражение LambdaExpression в IncludeFilter следующим образом:

EDIT: я изменил свой тестовый код на следующий, так как (правильно) я не выполнял инструкцию «Where». Правильный оператор where генерируется, но я не могу передать заявление лямбда в вызов IncludeFilter:

        DbSet<MyTestEntity> dbSet = db.Set<MyTestEntity>();
        ParameterExpression parameter = Expression.Parameter(typeof(MyTestEntity), "t");
        Expression idProperty = Expression.Property(parameter, "mytestentityid");
        Expression delProperty = Expression.Property(parameter, "deleted");
        Expression delTarget = Expression.Constant(false, typeof(bool));
        Expression deletedMethod = Expression.Call(delProperty, "Equals", null, delTarget);
        Expression<Func<MyTestEntity, bool>> lambda = Expression.Lambda<Func<MyTestEntity, bool>>(deletedMethod, parameter);
        IQueryable<MyTestEntity> query = dbSet.Where(lambda);
        Console.WriteLine("Current Query: {0}", query.ToString());
        foreach (string include in includes)
        {
            Type subType = db.GetType().Assembly.GetTypes().SingleOrDefault(x => x.Name.EndsWith(include));
            Assert.IsNotNull(subType);
            ParameterExpression innerParam = Expression.Parameter(subType, subType.Name);
            Assert.IsNotNull(innerParam);
            MemberExpression inrDelProp = Expression.Property(innerParam, "deleted");
            Assert.IsNotNull(inrDelProp);
            ConstantExpression inrDelCstProp = Expression.Constant(false, typeof(bool));
            Assert.IsNotNull(inrDelCstProp);
            MethodCallExpression inrDelMthd = Expression.Call(inrDelProp, "Equals", null, inrDelCstProp);
            Assert.IsNotNull(inrDelMthd);
            var delegateType = typeof(Func<,>).MakeGenericType(subType, typeof(bool));
            dynamic inrLmbdaExpr = Expression.Lambda(delegateType, inrDelMthd, innerParam);
            Assert.IsNotNull(inrLmbdaExpr);
            Console.WriteLine("inrLmbdaExpr: {0}", inrLmbdaExpr.ToString()); // Result: MyTestEntityChild => MyTestEntityChild.deleted.Equals(false)
            query = query.IncludeFilter(inrLmbdaExpr); // ERROR HERE
            Assert.IsNotNull(query);
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("Current Query: {0}", query.ToString());
        }

Он встроен в абстрактный класс, позволяющий мне передавать тип сущности, извлекать записи и повторно использовать метод независимо от типа объекта; однако я также пытаюсь отфильтровать дочерние объекты, помеченные как удаленные (таким образом, использование EF +).

Как я могу это сделать?

EDIT 2: Итак, я понял, что у меня также есть Linq.Dynamic.Core (!) В моем решении, поэтому у меня уже есть доступ к разбору LambdaExpression из строки. Тем не менее, ошибка, которую я получаю, говорит, что IncludeFilter не знает, какой метод он пытается использовать. (Я вижу в обозревателе объектов, что один использует выражение>, и один использует выражение>. Если бы я мог просто выяснить, как заставить IncludeFilter распознавать какой метод, я думаю, что я буду сделан! Вот пример кода I 'переписано:

string myIncStr = String.Format("x => x.{0}.Where(s => s.deleted.Equals(false)).Where(x => x.MyEntityId.Equals(IncomingId)",includedEntityName);
IEnumerable<MyEntity> result = db.MyEntity.IncludeFilter(System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(typeof(MyChildEntity), myIncStr, null));

Есть ли способ «заставить» (из-за отсутствия лучшего термина) IncludeFilter использовать один метод? Это, передавая значение вместо нуля в Parser?

Кстати, спасибо за вашу помощь. Ваша библиотека EFP на самом деле отличная.

Ответ эксперта

Отказ от ответственности : Я являюсь владельцем проекта Entity Framework Plus

Да, это возможно, но только если вы можете указать QueryFilter тип аргумента, необходимый для метода явно для QueryFilter (как вы упомянули в своем комментарии).

В противном случае вам нужно будет также вызвать QueryFilter помощью выражения, чтобы сделать все общим.


Однако ваше текущее выражение, похоже, имеет некоторые ошибки, такие как не вызов методов Where .

То, что вы хотите достичь, вероятно, похоже на это:

query = query.IncludeFilter(x => x.Childs.Where(y => !y.Deleted));


Отказ от ответственности : Я являюсь владельцем проекта Eval-Expression.NET

Эта библиотека не является бесплатной, но упрощает и ускоряет работу с динамическим выражением.

Как только вы привыкнете, вы можете быстро создать динамическое выражение только в нескольких строках, поскольку вы обычно пишете LINQ. Вот код, который может обрабатывать аналогичный сценарий, как ваш:

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Windows.Forms;
using Z.Expressions;

namespace Z.EntityFramework.Plus.Lab.EF6
{
    public partial class Form_Request_IncludeFilter_Dynamic : Form
    {
        public Form_Request_IncludeFilter_Dynamic()
        {
            InitializeComponent();

            // CLEAN
            using (var context = new EntityContext())
            {
                context.MyEntityClasses.RemoveRange(context.MyEntityClasses);
                context.MyEntityClassToFilters.RemoveRange(context.MyEntityClassToFilters);
                context.SaveChanges();
            }

            // SEED
            using (var context = new EntityContext())
            {
                var entity1 = context.MyEntityClasses.Add(new MyEntityClass {ColumnInt = 1, Childs = new List<MyEntityClassToFilter>()});
                entity1.Childs.Add(new MyEntityClassToFilter {ColumnInt = 1, Deleted = true});
                entity1.Childs.Add(new MyEntityClassToFilter {ColumnInt = 2, Deleted = false});
                context.MyEntityClasses.Add(new MyEntityClass {ColumnInt = 2});
                context.MyEntityClasses.Add(new MyEntityClass {ColumnInt = 3});
                context.SaveChanges();
            }

            // TEST
            using (var context = new EntityContext())
            {
                // You must register extension method only once
                // That should not be done here, but for example purpose
                EvalManager.DefaultContext.RegisterExtensionMethod(typeof(QueryIncludeFilterExtensions));

                // That could be also dynamic. I believe you already handle this part
                IQueryable<MyEntityClass> query = context.MyEntityClasses;

                // The path to include
                var include = "Childs";

                // The dynamic expression to execute
                var dynamicExpression = "IncludeFilter(x => x." + include + ".Where(y => !y.Deleted));";
                query = query.Execute<IQueryable<MyEntityClass>>(dynamicExpression);

                // The result
                var list = query.ToList();
            }
        }

        public class EntityContext : DbContext
        {
            public EntityContext() : base("CodeFirstEntities")
            {
            }

            public DbSet<MyEntityClass> MyEntityClasses { get; set; }
            public DbSet<MyEntityClassToFilter> MyEntityClassToFilters { get; set; }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Types().Configure(x =>
                    x.ToTable(GetType().DeclaringType != null
                        ? GetType().DeclaringType.FullName.Replace(".", "_") + "_" + x.ClrType.Name
                        : ""));

                base.OnModelCreating(modelBuilder);
            }
        }

        public class MyEntityClass
        {
            public int ID { get; set; }
            public int ColumnInt { get; set; }

            public List<MyEntityClassToFilter> Childs { get; set; }
        }

        public class MyEntityClassToFilter
        {
            public int ID { get; set; }
            public int ColumnInt { get; set; }

            public bool Deleted { get; set; }
        }
    }
}

EDIT: ответьте на вопрос

Просмотрите измененный код

Вам все еще не хватает предложения where .

То, что у вас есть, похоже на это, как вы прокомментировали

// Result: MyTestEntityChild => MyTestEntityChild.deleted.Equals(false)

То, что вы хотите, похоже на это

// Result: MyTestEntityChild => MyTestEntityChild.Where(x => x.deleted.Equals(false))

EDIT: ответьте на вопрос

Извините, теперь я понимаю проблему с этим.

Если вы не знаете тип, вам нужно будет вызвать IncludeFilter в выражении, а также сделать все общее. Его нельзя назвать явно так, как вы пытаетесь сделать.





Лицензировано согласно: CC-BY-SA
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему