解决方案:
string queryField = "Parent.NewsArticles.Title";
var parent = Expression.Parameter(typeof(Parent), "p");
var split = queryField.Split(".");
var propertyA = Expression.Property(parent, split[1]);
var propertyB = Expression.Property(Expression.Parameter(propertyA.Type.GetGenericArguments().First(), "a"), split[2]);
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsExpression = Expression.Call(propertyB, containsMethod, Expression.Constant("economy"));
var anyMethod = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).First();
var genericAnyMethod = anyMethod.MakeGenericMethod(propertyA.Type.GetGenericArguments().First());
var anyExpression = Expression.Call(null, genericAnyMethod, propertyA, Expression.Lambda(containsExpression, Expression.Parameter(propertyA.Type.GetGenericArguments().First(), "a")));
var whereMethod = typeof(Queryable).GetMethods().Where(m => m.Name == "Where" && m.GetParameters().Length == 2).First();
var genericWhereMethod = whereMethod.MakeGenericMethod(typeof(Parent));
var whereExpression = Expression.Call(null, genericWhereMethod, Expression.Constant(DbSet<Parent>()), Expression.Lambda(anyExpression, parent));
你犯的错误以及我如何纠正它们:
您在创建表达式树时犯了一个错误。具体来说,在第 4 步中,您为拆分数组的第二个元素 propertyA 字段创建了一个表达式,但是您应该使用拆分数组的第一个元素为 propertyA 字段创建一个表达式,这是Parent 类型的属性。这是因为您要访问 Parent 类型的 NewsArticles 属性,而不是 propertyA。
我通过更改步骤 4 中的表达式以访问父表达式参数的属性 split[0] 来更正此问题,如下所示:var propertyA = Expression.Property(parent, split[0]);。
在第 6 步中,您试图在字符串类型上找到 Contains 方法,但您需要在 propertyB 的类型上使用 Contains 方法,它可以是任何数据类型。我通过将行更改为 var containsMethod = propertyB.Type.GetMethod("Contains", new[] { typeof(string) }); 来解决这个问题。
在第 8 步中,您试图在 Enumerable 类型上找到 Any 方法,但您需要在 propertyA 的类型上使用 Any 方法,它是一个 ICollection 类型。我通过将行更改为 var anyMethod = propertyA.Type.GetMethod("Any"); 来解决这个问题。
通过这些更改,表达式树将正确地评估为如下内容:
DbSet<Parent>().Where(p => p.NewsArticles.Any(n => n.Title.Contains("economy")));.