LINQ to Entities - 使用字符串名称寻址类属性

时间:2014-01-28 20:54:07

标签: c# linq entity-framework asp.net-mvc-4 kendo-grid

我有一个已打开服务器端过滤的Kendo网格。要过滤的字段作为字符串传递。例如,我想过滤“SampleId”。现在,我需要编写一个LINQ to Entities查询,该查询可以使用强类型属性SampleId进行过滤。例如:

    db.Cases.Where(x=>targetlist.Contains(x.SampleId))

其中targetlist是过滤器中的项目列表。

那么,实际上,有没有办法编写一个查询,以便“SampleId”可以直接转换为Case.SampleId?

我尝试过反射并使用了GetProperty和GetValue,LINQ to Entities不喜欢它。

任何建议都将不胜感激!


编辑(通过原始海报srinaik2020的pid):

@zaitsman:这是在下面的评论中发布的代码,它是问题的实际解决方案,基于接受的答案。

public static class MyExtensions
{
    public static string GetPropertyByName(this CaseV case1, string name)
    {
        var x = typeof (CaseV).GetProperty(name).GetValue(case1);

        if (x != null)
        {
            return x.ToString();
        } else {
            return "none";
        }
    }
}

3 个答案:

答案 0 :(得分:1)

我认为这些方法都没有真正回答如何进行getproperty,因此在进一步研究之后将我的工作代码包括在内。 mymodelclass是用于MyFilteredData的实体/模型的类。

        var srchItem1 = typeof(mymodelclass).GetProperty("Name");
        var srchItem2 = typeof(mymodelclass).GetProperty("Description");
        var srchItem3 = typeof(mymodelclass).GetProperty("LongDescription");
        if (MySearchText != null && srchItem1 != null)
            {
                if (srchItem2 == null) { srchItem2 = srchItem1; }
                if (srchItem3 == null) { srchItem3 = srchItem1; }
                MyFilteredData = MyFilteredData.
                        Where(c => srchItem1.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower()) ||
                        srchItem2.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower()) ||
                        srchItem3.GetValue(c).ToString().ToLower().Contains(MySearchText.ToLower())
                );
            }

答案 1 :(得分:0)

您可以使用扩展方法并将其附加到班级。

该方法应使用反射从对象中检索属性。

以下是指示:

一旦这个工作,你只需要设置和/或获取属性的值。 上面的GetProperty()方法只返回PropertyInfo对象。 要获取或设置值,您必须使用PropertyInfo的适当方法。

我不会公开PropertyInfo,因为它会毁掉魔法。

最好是扩展方法,然后:

T GetPropertyByName<T>(string name);
SetPropertyByName<T>(string name, T value);

答案 2 :(得分:0)

如果您喜欢表达式,可以使用它们来获取属性的值(取自我在LinqPad中创建的一些帮助程序,因此它可能不是完整代码):

public static class Helper {

    public static IEnumerable<T> Select<T>( this IEnumerable enumerable, string memberName ) {
        IQueryable queryable = enumerable.AsQueryable();
        LambdaExpression expression = PredicateFor( queryable.ElementType, memberName );
        return CreateQuery( queryable, "Select", new[] { expression.ReturnType }, expression ).Cast<T>();
    }

    public static MemberExpression NestedPropertyOrField(this Expression expression, string nestedPropertyOrFieldName) {
        MemberExpression e;

        if (nestedPropertyOrFieldName.IndexOf('.') >= 0) {
            var split = nestedPropertyOrFieldName.Split(new[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);

            if (split.Length > 0) {
                e = Expression.PropertyOrField(expression, split[0]);

                if (split.Length > 1) {
                    e = NestedPropertyOrField(e, split[1]);
                }
            } else {
                throw new ArgumentException("'" + nestedPropertyOrFieldName + "' is not a member of type '" + expression.Type.AssemblyQualifiedName + "'");
            }
        } else {
            e = Expression.PropertyOrField(expression, nestedPropertyOrFieldName);
        }

        return e;
    }

    private static IEnumerable CreateQuery( IEnumerable enumerable, string method, Type[] typeArguments, params Expression[] arguments ) {
        IQueryable queryable = enumerable.AsQueryable();
        Type[] typeArgs = new[] { queryable.ElementType }.Concat( typeArguments ?? new Type[ 0 ] ).ToArray();
        Expression[] args = new[] { queryable.Expression }.Concat( arguments ?? new Expression[ 0 ] ).ToArray();
        MethodCallExpression methodCallExpression = Expression.Call( typeof( Queryable ), method, typeArgs, args );
        return queryable.Provider.CreateQuery( methodCallExpression );
    }

    internal static LambdaExpression PredicateFor( Type elementType, string memberName ) {
        var pe = Expression.Parameter( elementType, "@item" );
        Expression expression = pe;

        if ( memberName.StartsWith( "@item", StringComparison.OrdinalIgnoreCase ) ) {
            memberName = memberName.Substring( 5 );
        }

        if ( memberName.Length > 0 )
            expression = NestedPropertyOrField( expression, memberName );

        var delegateType = Expression.GetFuncType( elementType, expression.Type );
        return Expression.Lambda( delegateType, expression, new[] {pe} );
    }
}

然后再做

string propertyName = // get property name from somewhere, ie: "SomeObject.NestedProperty.ID"
db.Cases.Select<string>(propertyName).Where(targetlist.Contains);