2

我在 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;
}

在我有“使用密钥字符串作为字段名”的地方,它就像 p => p.FirstName == fieldValueDictionary[key] where key = "FirstName"。我尝试过使用 Lambda 表达式树但失败了,并且在 Dynamic 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>();
}

更新:我通过以下帖子对 Lambda 表达式树进行了研究:

动态创建 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);
4

3 回答 3

8

经过更多的反复试验和搜索,我意外地发现了另一个涵盖相同问题的 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);

通过一些希望非常简单的修改,我应该能够让它适用于任何类型。

再次感谢您的回答 Ani & John Bowen

于 2010-08-12T16:15:45.133 回答
5

Have you tried getting the value from PropertyInfo?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])
于 2010-08-11T23:03:07.667 回答
1
  public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
        {
            return !fieldValueDictionary.Any()
                   ? entities.People 
                   : entities.People.Where(p => fieldValueDictionary.All(kvp => PropertyStringEquals(p, kvp.Key, kvp.Value)))
                                    .ToList();
        }

  private bool PropertyStringEquals(object obj, string propertyName, string comparison)
        {
            var val = obj.GetType().GetProperty(propertyName).GetValue(obj, null);
            return val == null ? comparison == null : val.ToString() == comparison; ;
        }
于 2010-08-11T23:01:33.923 回答