【问题标题】:Like search for datetime fields using dynamic lambda expression就像使用动态 lambda 表达式搜索日期时间字段一样
【发布时间】:2013-02-08 11:22:51
【问题描述】:

我正在形成如下的字符串表达式。

     string Condition = " it.person_id = " + personId.ToString();

     if (lstPersonFields != null)
      {
         foreach (var field in lstPersonFields )
           {                           
              string  fieldCondition = " And it." + field.FieldName.ToString();
                if (field.FieldCondition == "Contains")
                  {
                    fieldCondition = fieldCondition + " Like '%" + field.FieldValue.ToString() + "%'";
                  }
                 else if (field.FieldCondition == "Equals")
                  {
                   fieldCondition = fieldCondition + " = '" + field.FieldValue.ToString()+"'";
                  }
                 Condition = Condition + fieldCondition;
           }
      }
      var personSearch = FullPersonlst.Where(Condition).ToList();

以上代码在类似搜索中对日期时间值以外的其他值正常工作,并为类似日期时间字段抛出错误

Like arguments must be of string type 

如何搜索日期时间字段?

【问题讨论】:

  • 您是否尝试将日期时间转换为字符串..?
  • 我认为在这种情况下不可能,因为我们没有字段名称。
  • 不要连接输入。重复:不要连接输入。这是非常非常非常危险的代码...
  • @User_MVC 因为它非常容易受到 SQL 注入的影响。如果您不熟悉 SQL 注入,请立即查找。这是最普遍的非法获取数据、破坏数据的方式。如果您经常编写上述代码,那么您的系统根本就坏了,需要立即引起注意。

标签: c# asp.net-mvc linq lambda


【解决方案1】:

将其作为动态 lambda 表达式执行如下操作:

var arg = Expression.Parameter(typeof(Person), "it");
var body = Expression.Equal(
    Expression.PropertyOrField(arg, "PersonId"),
    Expression.Constant(personId));

if (lstPersonFields != null)
{
    foreach (var field in lstPersonFields)
    {
        var member = Expression.PropertyOrField(arg, field.FieldName);
        switch (field.FieldCondition)
        {
            case "Contains":
                body = Expression.AndAlso(body,
                    Expression.Call(typeof(SqlMethods), "Like", null,
                        member,
                        Expression.Constant("%" + field.FieldValue + "%")));
                break;
            case "Equals":
                body = Expression.AndAlso(body,
                    Expression.Equal(
                       member,
                       Expression.Constant(field.FieldValue)));
                break;
        }
    }
}
var lambda = Expression.Lambda<Func<Person,bool>>(body, arg);
var personSearch = FullPersonlst.Where(lambda).ToList();

【讨论】:

  • 当我将上述代码转换为 LINQ to Entities 时,它会抛出此错误,例如:LINQ to Entities 无法识别方法 'Boolean Like(System.String, System.String)' 方法,以及此方法无法转换为商店表达式。
  • 那个版本 (SqlMethods) 是 LINQ-to-SQL - 所以是的,它可能在 EF 中不起作用;您也可以只使用Contains - 即Expression.Call(member, "Contains", null, Expression.Constant(field.FieldValue)),或者更多选项,请参见此处:stackoverflow.com/questions/1033007/…
  • @Marc Gravell:上面的代码不适用于日期时间值。似乎需要对代码进行一些更改。您能告诉我如何修改此代码以使用日期时间值。
  • @User 在“ToString”上添加一些 Expression.Convert(到字符串)或 Expression.Call。或者采用 DateTime 输入并使用 Equal 等
  • @Marc 我确实喜欢这个 System.Reflection.PropertyInfo prop = typeof(vw_directory_search).GetProperty(field.FieldName); body = Expression.AndAlso(body, Expression.Call(member, "Equals", null, Expression.Convert(Expression.Constant(field.FieldValue), prop.PropertyType)));但它抛出错误没有强制运算符在类型'System.String'和'System.Nullable`1 [System.DateTime]'之间定义。
【解决方案2】:

正如错误所说,您不应该将 like 用于非字符串值。这也没有任何意义。如果要搜索特定的日期时间,请使用 datetime = value。为了在您可以使用的时间范围内搜索。您需要检查要搜索的属性类型,并使用适当的方式在查询中拟合类型。

就个人而言,我永远不会使用这样的“动态查询创建器”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多