다음과 같이 동적으로 생성 된 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를 호출해야합니다. 당신이하려는 것처럼 명시 적으로 호출 할 수 없습니다.