c# - 从表达式中的集合访问嵌套属性

标签 c# linq expression

好的,稍微设置上下文我正在使用此类使用表达式树构建动态 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 的字符串和值的字符串,因此当我查询时,例如条件看起来像

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]'

非常感谢任何帮助

--编辑--

在尝试了 Ivan 的回答后我得到了错误

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/

相关文章:

c# - XNA 纹理 2D 获取数据

c# - LINQ 执行查询 - 错误

ios - NSPredicate swift2 的最长时间

c++ - 是类型(::x);有效的?

c# - 序列化方法的比较

c# - 字符串类 Replace 和 Stringbuilder 替换

sql - Linq to sql - 连接 2 个表,从右表中选择具有一对多关系的 1 行

c# - MongoDB 和 C#,如何按星期比较

c# - DataTable 表达式无法解释标记 '!'

c# - 在 VS 2010 asp.net 中没有获取 gridview1.Rows.Clear() 选项