好的,稍微设置一下上下文,我正在使用这个类的表达式树构建一个动态linq搜索子句
public class HomeTableInvoice {
public int Sys_InvoiceID { get; set; }
public bool Turnover { get; set; }
public int FK_StatusID { get; set; }
public string InvoiceNumber { get; set; }
public DateTime InvoiceDate { get; set; }
public string DocType { get; set; }
public ICollection<InvoiceCustomFields> InvoiceCustomFields { get; set; }
}
我已经成功地使一切正常工作,我使用的参数是hometableinvoice,我可以使用
var parameter = Expression.Parameter(typeof(HomeTableInvoice), "invoice");
prop = Expression.Property(param, filter.SysName);
filter.sysname是我要筛选的字段。
当试图为底部的icollection构建表达式时,问题就来了。InvoiceCustomFields类包含
public class InvoiceCustomFields : CustomFieldsBase {
public int? FK_SysInvoiceID { get; set; }
public string FK_CustomFieldHeader { get; set; }
public string Value { get; set; }
}
我试图访问fkcustomfieldheader的字符串和value的字符串,因此当我查询示例时,条件可以如下所示
where InvoiceNumber == 34 AndAlso (Invoice.InvoiceCustomField.FK_CustomFieldHeader == "Test" && Invoice.InvoiceCustomField.FK_CustomFieldHeader.Value == 42)
我试过用
prop = Expression.PropertyOrField(Expression.PropertyOrField(param, "InvoiceCustomFields"), "FK_CustomFieldHeader");
但它抛出了这个错误
FK_CustomFieldHeader' is not a member of type 'System.Collections.Generic.ICollection`1[APData.Audit.Entityframework.Entities.InvoiceCustomFields]'
非常感谢您的帮助
--编辑--
在尝试了伊凡的答案后,我得到了错误
No generic method 'Any' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments
我试过了
prop = Expression.PropertyOrField(parameter, "InvoiceCustomFields");
var queryableType = typeof(Enumerable);
var whereMethod = queryableType.GetMethods()
.First(m => {
var parameters = m.GetParameters().ToList();
return m.Name == "Any" && m.IsGenericMethodDefinition &&
parameters.Count == 2;
});
MethodInfo methoInfo = whereMethod.MakeGenericMethod(prop.Type);
var x = Expression.Call(methoInfo, Expression.PropertyOrField(parameter, "InvoiceCustomFields"), whereQuery);
然后这个就扔了
Expression of type `'System.Collections.Generic.ICollection`1[InvoiceCustomFields]' cannot be used for parameter of type 'System.Linq.IQueryable`1[System.Collections.Generic.ICollection`1[InvoiceCustomFields]]' of method 'Boolean Any[ICollection`1](System.Linq.IQueryable`1[System.Collections.Generic.ICollection`1[InvoiceCustomFields]], System.Linq.Expressions.Expression`1[System.Func`2[System.Collections.Generic.ICollection`1[.InvoiceCustomFields],System.Boolean]])`
最佳答案
让我们看看如果它不是动态的。以下内容:
Expression<Func<HomeTableInvoice, bool>> predicate = invoice =>
invoice.InvoiceCustomField.FK_CustomFieldHeader == "Test" &&
invoice.InvoiceCustomField.Value == "42";
不是有效的表达式。
你实际上需要做的是这样的事情:
Expression<Func<HomeTableInvoice, bool>> predicate = invoice =>
invoice.InvoiceCustomFields.Any(field =>
field.InvoiceCustomField.FK_CustomFieldHeader == "Test" &&
field.InvoiceCustomField.Value == "42");
下面是如何动态构建的(希望您可以根据需要进行调整,用变量替换硬编码部分):
var parameter = Expression.Parameter(typeof(HomeTableInvoice), "invoice");
var fieldParameter = Expression.Parameter(typeof(InvoiceCustomFields), "field");
var anyPredicate = Expression.Lambda(
Expression.AndAlso(
Expression.Equal(
Expression.PropertyOrField(fieldParameter, "FK_CustomFieldHeader"),
Expression.Constant("Test")),
Expression.Equal(
Expression.PropertyOrField(fieldParameter, "Value"),
Expression.Constant("42"))),
fieldParameter);
var fieldCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { fieldParameter.Type },
Expression.PropertyOrField(parameter, "InvoiceCustomFields"), anyPredicate);
// You can use the fieldCondition in your combinator,
// the following is just to complete the example
var predicate = Expression.Lambda<Func<HomeTableInvoice, bool>>(fieldCondition, parameter);
// Test
var input = new List<HomeTableInvoice>
{
new HomeTableInvoice
{
InvoiceNumber = "1",
InvoiceCustomFields = new List<InvoiceCustomFields>
{
new InvoiceCustomFields { FK_CustomFieldHeader = "Test", Value = "42" }
}
},
}.AsQueryable();
var output = input.Where(predicate).ToList();
关于c# - 从表达式中的集合访问嵌套属性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39118338/