私は動的に生成されたLambdaExpressionをIncludeFilterに次のように渡そうとしています:
編集:(正確に)私の "どこ"のステートメントを実装していなかったので、私は次のように私のテストコードを変更しました。正しいwhere文が生成されていますが、lambda文を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));
1つのメソッドを使用するためにIncludeFilterを「強制」する(より良い用語がないために)方法はありますか?それはParserで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を呼び出して、すべてを汎用にする必要があります。あなたがしようとしているように明示的に呼び出すことはできません。