建立在儿童专有物体(集合)物体中搜索的表达

发布于 2025-01-28 06:15:09 字数 2755 浏览 3 评论 0原文

我有一个搜索设置,可以根据条件返回匹配记录对象。它根据标准的类型构建表达树,并查询数据库以返回匹配项。以前,它仅在顶级属性上匹配,但是现在我试图在record的儿童属性中搜索,并构建一种表达式,该表达式可以与查询中的其他表达式结合在一起。对象看起来像这样:

public class Record
{
    public virtual ICollection<Attribute> Attributes { get; set; }
}

public class Attribute
{
    public Guid AttributeId { get; set; }
    public string Value { get; set; }

    public virtual Record Record { get; set; }
}

可能的标准之一是一个值对attributeIdvalue,我将返回所有record> record row具有属性匹配两个值。例如,如果我只是写一个简单的linq查询,它看起来就是这样:

Guid searchId = Guid.NewGuid();
string searchValue = "asdf";

IQueryable<Record> records = GetSomeQueryToRecords();
IEnumerable<Record> recordsThatMatch = records
    .Where(r => r.Attribute.Any(a => a.AttributeId == searchId && a.Value == searchValue));

我需要将其构建到我的表达树中,以便它可以在内存和EF核心查询中起作用。 getexpression返回的表达式最终将与其他表达式结合使用andalso以在线构建大型查询。我已经尝试了以下操作:

ParameterExpression record = Expression.Parameter(typeof(Record));
Expression searchExpression = GetExpression(record, searchId, searchValue);

Expression<Func<Record, bool>> lambda = Expression.Lamda<Func<Record, bool>>(searchExpression, record);
recordsThatMatch = records.Where(lambda);


private Expression GetExpression(ParameterExpression parameter, Guid searchId, string searchValue)
{
    // Get the Record.Attributes Memboer.
    MemberExpression attributes = Expression.Property(parameter, nameof(Record.Attributes));

    // Get the "record.Attributes.Any(predicate)" Method.
    MethodInfo anyMethod = typeof(Enumerable).GetMethods()
        .Where(m => m.Name == nameof(Enumerable.Any))
        .Where(m => m.GetParameters().Length == 2)
        .Single();
    
    // Make Method generic.
    anyMethod = anyMethod.MakeGenericMethod(typeof(Attribute));

    ParameterExpression attribute = Expression.Parameter(typeof(Attribute));

    Expression idEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.AttributeId)),
        Expression.Constant(searchId)
    );

    Expression valueEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.Value)),
        Expression.Constant(searchValue)
    );

    Expression attributeMatchExpression = Expression.AndAlso(idEqualExpression, valueEqualExpression);

    return Expression.Call(null, anyMethod, attributes, attributeMatchExpression);
}

我从grognal exception带有expression.call,因为老实说,我不知道如何在此特定实例中使用它,并且它具有许多替代。我相信我应该传递null,因为我实际上想要一种静态方法.yany()()是一种扩展方法。

I have a search setup to return matching Record objects based on criteria. It builds an Expression Tree based on the type of criteria and queries the database to return matches. Previously, it only matched on top-level properties, but now I'm trying to search within child properties of Record and build an Expression that may be combined with others in a query. The objects look like this:

public class Record
{
    public virtual ICollection<Attribute> Attributes { get; set; }
}

public class Attribute
{
    public Guid AttributeId { get; set; }
    public string Value { get; set; }

    public virtual Record Record { get; set; }
}

One of the possible criteria is a value pair of AttributeId and Value, for which I would return all Record rows which have an Attribute matching both values. For example, if I was just writing a simple LINQ query it would look like this:

Guid searchId = Guid.NewGuid();
string searchValue = "asdf";

IQueryable<Record> records = GetSomeQueryToRecords();
IEnumerable<Record> recordsThatMatch = records
    .Where(r => r.Attribute.Any(a => a.AttributeId == searchId && a.Value == searchValue));

I need to instead build this into my Expression tree so it will work both in-memory and for EF Core queries. The Expression returned by GetExpression would end up being combined with other Expressions using AndAlso to build a large query down the line. I have tried this:

ParameterExpression record = Expression.Parameter(typeof(Record));
Expression searchExpression = GetExpression(record, searchId, searchValue);

Expression<Func<Record, bool>> lambda = Expression.Lamda<Func<Record, bool>>(searchExpression, record);
recordsThatMatch = records.Where(lambda);


private Expression GetExpression(ParameterExpression parameter, Guid searchId, string searchValue)
{
    // Get the Record.Attributes Memboer.
    MemberExpression attributes = Expression.Property(parameter, nameof(Record.Attributes));

    // Get the "record.Attributes.Any(predicate)" Method.
    MethodInfo anyMethod = typeof(Enumerable).GetMethods()
        .Where(m => m.Name == nameof(Enumerable.Any))
        .Where(m => m.GetParameters().Length == 2)
        .Single();
    
    // Make Method generic.
    anyMethod = anyMethod.MakeGenericMethod(typeof(Attribute));

    ParameterExpression attribute = Expression.Parameter(typeof(Attribute));

    Expression idEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.AttributeId)),
        Expression.Constant(searchId)
    );

    Expression valueEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.Value)),
        Expression.Constant(searchValue)
    );

    Expression attributeMatchExpression = Expression.AndAlso(idEqualExpression, valueEqualExpression);

    return Expression.Call(null, anyMethod, attributes, attributeMatchExpression);
}

I get an ArgumentException with Expression.Call though, because honestly I don't know how to use it for this particular instance and it has many overrides. I believe I should be passing null since I actually want a static method as .Any() is an extension method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

裂开嘴轻声笑有多痛 2025-02-04 06:15:09

您忘了创建“ Lambdaexpresson”。另外expression.call可以被插入。

private Expression GetExpression(ParameterExpression parameter, Guid searchId, string searchValue)
{
    // Get the Record.Attributes Memboer.
    MemberExpression attributes = Expression.Property(parameter, nameof(Record.Attributes));

    ParameterExpression attribute = Expression.Parameter(typeof(Attribute));

    Expression idEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.AttributeId)),
        Expression.Constant(searchId)
    );

    Expression valueEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.Value)),
        Expression.Constant(searchValue)
    );

    Expression attributeMatchExpression = Expression.AndAlso(idEqualExpression, valueEqualExpression);

    var matchLambda = Expression.Lambda(attributeMatchExpression, attribute);

    return Expression.Call(typeof(Enumerable), nameof(Enumerable.Any), new [] {typeof(Attribute)}, attributes, matchLambda);
}

You have forgot to create 'LambdaExpresson'. Also Expression.Call can besimplified.

private Expression GetExpression(ParameterExpression parameter, Guid searchId, string searchValue)
{
    // Get the Record.Attributes Memboer.
    MemberExpression attributes = Expression.Property(parameter, nameof(Record.Attributes));

    ParameterExpression attribute = Expression.Parameter(typeof(Attribute));

    Expression idEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.AttributeId)),
        Expression.Constant(searchId)
    );

    Expression valueEqualExpression = Expression.Equal(
        Expression.Property(attribute, nameof(Attribute.Value)),
        Expression.Constant(searchValue)
    );

    Expression attributeMatchExpression = Expression.AndAlso(idEqualExpression, valueEqualExpression);

    var matchLambda = Expression.Lambda(attributeMatchExpression, attribute);

    return Expression.Call(typeof(Enumerable), nameof(Enumerable.Any), new [] {typeof(Attribute)}, attributes, matchLambda);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文