使用Dyanmic字段名称使用LINQ查询实体

Sco*_*nce 2 c# lambda linq-to-entities expression-trees dynamic-linq

我在ASP.NET MVC中创建了一个动态搜索屏幕.我通过反射从实体中检索了字段名称,这样我就可以允许用户选择要搜索的字段而不是显示视图中的所有字段.

当搜索结果回发到控制器时,我收到一个包含FieldName和Value的FormCollection.我不知道搜索了多少字段,FormCollection只包含用户选择的字段.

我希望现在能够获取该字段名称并在我查询数据库时将其应用于我的LINQ语句,例如:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    List<People> searchResults = new List<People>();

    foreach (string key in fieldValueDictionary.Keys)
    {
         searchResults.Add(entities.People.Where(p => p.<use the key string as the fieldName> == fieldValueDictionary[key]));
    }

    return searchResults;
}
Run Code Online (Sandbox Code Playgroud)

我在"使用键字符串作为fieldName"的地方就像p => p.FirstName == fieldValueDictionary [key]其中key ="FirstName".我尝试过并且未能使用Lambda Expression Trees,并且在动态LINQ方面取得了一些成功.唯一的另一种选择是做类似的事情:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    IQueryable<People> results = entities.People;

    foreach (string key in fieldValueDictionary.Keys)
    {
         switch (k)
         {
             case "FirstName": results = results.Where(entities.People.Where(p => p.FirstName == k);
             case "LastName": results = results.Where(entities.People.Where(p => p.LastName == k);
             // Repeat for all 26 fields in table
         }
    }

    return results.ToList<People>();
}
Run Code Online (Sandbox Code Playgroud)

更新:我通过以下帖子研究了Lambda Expression Trees:

动态创建lambdas表达式+ linq + OrderByDescending

Expression.Lambda()的参数问题

LINQ:将lambda表达式作为参数传递,由方法执行并返回

我已经得到一个lambda来输出以下内容:"p => p.FirstName",但我不能让它在哪里工作.有什么建议?我的代码如下:

MemberInfo member = typeof(People).GetProperty("FirstName");
ParameterExpression cParam = Expression.Parameter(typeof(People), "p");    
Expression body = Expression.MakeMemberAccess(cParam, member);        

var lambda = Expression.Lambda(body, cParam);
Run Code Online (Sandbox Code Playgroud)

Sco*_*nce 7

经过更多的反复试验和搜索后,我偶然发现了另一个涉及同一问题的SO帖子:

InvalidOperationException:类型'System.Linq.Queryable'上没有方法'Where'与提供的参数兼容

这是我修改后的代码:

        IQueryable query = entities.People;
        Type[] exprArgTypes = { query.ElementType };

        string propToWhere = "FirstName";            

        ParameterExpression p = Expression.Parameter(typeof(People), "p");
        MemberExpression member = Expression.PropertyOrField(p, propToWhere);
        LambdaExpression lambda = Expression.Lambda<Func<People, bool>>(Expression.Equal(member, Expression.Constant("Scott")), p);                            

        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), "Where", exprArgTypes, query.Expression, lambda);

        IQueryable q = query.Provider.CreateQuery(methodCall);
Run Code Online (Sandbox Code Playgroud)

通过一些希望非常容易的修改,我应该能够使用任何类型.

再次感谢您的答案Ani和John Bowen


Joh*_*wen 5

您是否尝试过从PropertyInfo获取价值?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])
Run Code Online (Sandbox Code Playgroud)

  • Linq to Entities不支持GetValue()调用.我可以让这个想法发挥作用,但是它要求我从数据库中获取人员的完整列表,然后通过它们进行预测,它比我更清洁,但仍然不是我想要的. (2认同)