建立在儿童专有物体(集合)物体中搜索的表达
我有一个搜索设置,可以根据条件返回匹配记录
对象。它根据标准的类型构建表达树,并查询数据库以返回匹配项。以前,它仅在顶级属性上匹配,但是现在我试图在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; }
}
可能的标准之一是一个值对attributeId
和value
,我将返回所有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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您忘了创建“ Lambdaexpresson”。另外
expression.call
可以被插入。You have forgot to create 'LambdaExpresson'. Also
Expression.Call
can besimplified.