2017-02-18 32 views
1

如何传递一个实体属性作为LINQ表达式的参数?如何传递一个实体属性作为LINQ表达式的参数?

public DropdownFilter(WhatTypeHere? ABC) 
{ 
    // I want to store a selected property here 
    // ABC must be a property of TEntity 
    this.ABC = ABC; 
} 

// I want the class to encapsulate a LINQ query and just parametrize it with a property 
public override IQueryable<TEntity> Filter(IQueryable<TEntity> filteredEntityCollection, string value) 
{ 
    // ABC is a property of TEntity 
    return filteredEntityCollection.Where(this.ABC == value); 
} 

我会用这样的:

new DropdownFilter<Invoice>(invoice => invoice.SomeProperty); 

我已经与Expression<Func<TEntity, string>>各种参数的尝试,但没有成功。这是抱怨

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 

回答

1

你必须手动建立LINQ表达式。首先,我想第二个泛型参数添加到您的类,这将指定的属性和价值型类型,你会传递给过滤:

public class DropdownFilter<TEntity, TProperty> 

接下来,你应该通过属性选择器表达式来此过滤器类的构造函数:

private PropertyInfo propertyInfo; 

public DropdownFilter(Expression<Func<TEntity, TProperty>> propertySelector) 
{ 
    this.propertyInfo = (PropertyInfo)((MemberExpression)propertySelector.Body).Member; 
} 

而且最后,构建λ表达式通过指定属性的给定值来过滤的可查询:

public IQueryable<TEntity> Filter(
    IQueryable<TEntity> filteredEntityCollection, TProperty value) 
{ 
    var param = Expression.Parameter(typeof(TEntity), "p"); 

    var lambda = Expression.Lambda<Func<TEntity, bool>>(    
     Expression.Equal(
      Expression.Property(param, propertyInfo), 
      Expression.Constant(value) 
     ), param); 

    return filteredEntityCollection.Where(lambda); 
} 

用法:

var filter = new DropdownFilter<Invoice, string>(i => i.ABC); 
var result = filter(db.Invoices, "foo"); // strongly-typed parameter here 

我会添加传递给构造函数的属性选择器表达式的验证。你应该检查它是否是MemberExpression。而且你可以确定属性类型只支持原始类型的属性。

+1

这很棒,我相信它会起作用,但是我不知道如何向上传播'TProperty' ......因为我所有的'filters'都是从基类继承的,它被用作另一个对象的列表属性... –

+0

@HristoYankov好吧,你可以删除TProperty,或者使用'string'(但你应该检查'propertyInfo.PropertyType'是字符串),或者你可以使用'object'作为值,并通过'Expression.Convert(Expression.Constant(value),propertyType)将其转换为属性类型' –

相关问题