C# LINQ到实体-使用字符串名称寻址类属性

C# LINQ到实体-使用字符串名称寻址类属性,c#,linq,entity-framework,asp.net-mvc-4,kendo-grid,C#,Linq,Entity Framework,Asp.net Mvc 4,Kendo Grid,我有一个剑道网格,打开了服务器端过滤。要筛选的字段作为字符串传递。例如,我想按“SampleId”进行过滤。现在,我需要编写一个LINQtoEntities查询,该查询可以使用强类型属性SampleId进行过滤。例如: db.Cases.Where(x=>targetlist.Contains(x.SampleId)) 其中targetlist是筛选器中的项目列表 那么,实际上,有没有一种方法可以编写一个查询,使得“SampleId”可以直接转换为Case.SampleId 我尝

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

    db.Cases.Where(x=>targetlist.Contains(x.SampleId))
其中targetlist是筛选器中的项目列表

那么,实际上,有没有一种方法可以编写一个查询,使得“SampleId”可以直接转换为Case.SampleId

我尝试了反射,并使用了GetProperty和GetValue,而LinqTo实体不喜欢它

任何建议都将不胜感激


编辑(原始海报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";
        }
    }
}

可以使用扩展方法并将其附加到类

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

以下是要点:

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

我不会公开
属性info
,因为它会破坏魔法

最好使用扩展方法,然后:

T GetPropertyByName<T>(string name);
SetPropertyByName<T>(string name, T value);
T GetPropertyByName(字符串名称);
SetPropertyByName(字符串名称,T值);

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

公共静态类帮助器{
公共静态IEnumerable选择(此IEnumerable可枚举,字符串memberName){
IQueryable queryable=可枚举的.AsQueryable();
LambdaExpression expression=PredicateFor(queryable.ElementType,memberName);
返回CreateQuery(可查询,“选择”,新建[]{expression.ReturnType},expression).Cast();
}
公共静态成员表达式NestedPropertyOrField(此表达式,字符串nestedPropertyOrFieldName){
成员表达e;
如果(nestedPropertyOrFieldName.IndexOf('.')>=0){
var split=nestedPropertyOrFieldName.split(新[]{.'},2,StringSplitOptions.RemoveEmptyEntries);
如果(拆分长度>0){
e=表达式.PropertyOrField(表达式,拆分[0]);
如果(拆分长度>1){
e=嵌套属性或字段(e,拆分[1]);
}
}否则{
抛出新ArgumentException(““+nestedPropertyOrFieldName+””不是“+expression.type.AssemblyQualifiedName+”类型的成员);
}
}否则{
e=表达式.PropertyOrField(表达式,nestedPropertyOrFieldName);
}
返回e;
}
私有静态IEnumerable CreateQuery(IEnumerable可枚举、字符串方法、类型[]typeArguments、参数表达式[]参数){
IQueryable queryable=可枚举的.AsQueryable();
Type[]typeArgs=new[]{queryable.ElementType}.Concat(类型参数??新类型[0]).ToArray();
表达式[]args=new[]{queryable.Expression}.Concat(参数??新表达式[0]).ToArray();
MethodCallExpression MethodCallExpression=Expression.Call(typeof(Queryable),method,typeArgs,args);
返回queryable.Provider.CreateQuery(methodCallExpression);
}
内部静态LambdaExpression谓词(类型elementType,字符串memberName){
var pe=Expression.Parameter(elementType,“@item”);
表达式=pe;
if(memberName.StartsWith(“@item”,StringComparison.OrdinalIgnoreCase)){
memberName=memberName.Substring(5);
}
如果(memberName.Length>0)
表达式=NestedPropertyOrField(表达式,memberName);
var delegateType=Expression.GetFuncType(elementType,Expression.Type);
返回表达式.Lambda(delegateType,表达式,new[]{pe});
}
}
然后呢

string propertyName = // get property name from somewhere, ie: "SomeObject.NestedProperty.ID"
db.Cases.Select<string>(propertyName).Where(targetlist.Contains);
string propertyName=//从某处获取属性名,即:“SomeObject.NestedProperty.ID”
Select(propertyName).Where(targetlist.Contains);

我认为这些都没有回答如何执行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())
                );
            }

如果要在
IQueryable
上调用该方法,只需在
IQueryable
上调用它,不要在
IEnumerable
上调用它并尝试转换它。这对您来说需要做更多的工作,并向调用者暗示它将在LINQ to对象中执行这项工作。这样做是为了让一个方法可以处理IQueryable、ITable、DbSet、IEnumerable等@DariusL。我想OP想要的就是这个(您省略的部分)
stringpropertyname=//从某处获取属性名
。从强类型属性中获取属性名您可以只为
IQueryable
编写属性名,如果有人想将使用LINQ的对象传递给对象,他们可以自己使用
AsQueryable
。这种方法在处理表达式方面也过于冗长,尤其脆弱。使用EF这样的方法的关键是避免这样做。其思想是具有编译时类型安全性。如果您不想这样做,就不要使用整个功能,而是返回到一种更传统的参数化查询方法,以字符串形式输出。谢谢!添加一个扩展方法并调用它使LINQ对Entity保持满意。@zaitsman不确定放代码的最佳位置。。。所以只是把它贴在这里。。。如果你在找别的东西,请告诉我公共静态类MyEx
        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())
                );
            }