【问题标题】:Create Expression for Any为任何创建表达式
【发布时间】:2023-02-04 06:55:40
【问题描述】:

我正在尝试创建一个表达式,其计算结果如下:

DbSet<Parent>().Where(x => x.PropertyA.Any(p => p.PropertyB.Contains("...")));

PropertyA(它是一个 ICollection<PropertyA_Item>)和 PropertyB(可以是任何数据类型)由带“.”的字符串确定。分隔符(例如"NewsArticles.Title")。

我有类似以下内容:

string queryField = "Parent.NewsArticles.Title";
var parent = Expression.Parameter(typeof(parent), "p");
var split = queryField.Split(".");

var propertyA = Expression.Property(parent, split[1]); //evaluates to {Parent.NewsArticles}

我想我必须做这样的事情,但不确定:

var anyMethod = typeof(Enumerable).GetMember("Any").OfType<MethodInfo>().Where(m => m.GetParameters().Length == 2).First();
var genericAnyMethod = anyMethod.MakeGenericMethod(propertyA.Type)

因此,如果我想找到一个包含“经济”一词的标题,我将如何从我拥有的东西变成类似的东西:

DbSet<Parent>().Where(p => p.NewsArticles.Any(n => n.Title.Contains("economy")));

【问题讨论】:

    标签: c# linq-expressions


    【解决方案1】:

    解决方案:

    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")));.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-04
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多