IncludeFilter에 LambdaExpression을 전달하려면 어떻게해야합니까?

entity-framework entity-framework-plus

문제

다음과 같이 동적으로 생성 된 LambdaExpression을 IncludeFilter에 전달하려고합니다.

편집 : 나는 (정확히) 내 "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 + 사용).

어떻게해야합니까?

편집 2 : 그래서, 나는 또한 Linq.Dynamic.Core (!) 내 솔루션에, 그래서 이미 문자열에서 LambdaExpression을 구문 분석에 액세스 할 수있다 깨달았다. 그러나 내가 얻은 오류는 IncludeFilter가 어떤 방법을 사용하려고하는지 알지 못한다고합니다. (개체 브라우저에서 Expression>을 사용하고 Expression >>을 사용하는 것을 볼 수 있습니다. IncludeFilter를 통해 어떤 메서드를 인식 할 수 있는지를 알아낼 수 있다면 어떻게해야할까요? 재 작성 :

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를 "강제 적용"하는 방법이 있습니까? 파서에 null 대신 값을 전달 하는가?

안녕, 도와 줘서 고마워. EFP 라이브러리는 실제로 우수합니다.

전문가 답변

면책 조항 : 저는 Entity Framework Plus 프로젝트의 소유자입니다.

그렇습니다.하지만 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; }
        }
    }
}

수정 : 답변 질문

변경된 코드를 검토하십시오.

여전히 where 절이 누락되었습니다.

당신이 가지고있는 것은 당신이 논평 한 것과 비슷한 것입니다.

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

네가 원하는 것은 이것과 비슷한 것이다.

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

수정 : 답변 질문

죄송합니다. 이제 문제를 이해합니다.

형식을 모르는 경우 모든 것을 일반화하기 위해 식에서 IncludeFilter를 호출해야합니다. 당신이하려는 것처럼 명시 적으로 호출 할 수 없습니다.




아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.