【问题标题】:C# Dynamic Linq: Implement "Like" in The Where ClauseC# Dynamic Linq:在 Where 子句中实现“Like”
【发布时间】:2019-08-29 04:35:49
【问题描述】:

所以我想为我的数据制作一个通用分类器。我有这段代码可以从数据库中获取数据,它将仅提取包含 value 的数据。

using System.Linq.Dynamic;

public static IQueryable<object> SortList(string searchString, Type modelType, 
    IQueryable<object> model)
{
    ....

    string toStringPredicate = type == typeof(string) ? propertyName + 
        ".Contains(@0)" : propertyName + ".ToString().Contains(@0)";
    model = model.Where(propertyName + " != NULL AND " + toStringPredicate, value);
}

型号是这样的:

public class ManageSubscriberItems
{
    public int? UserId { get; set; }
    public string Email { get; set; }
    public Guid SubscriberId { get; set; }
}

当我打电话时:

models = (IQueryable<ManageSubscriberItems>)EcommerceCMS.Helpers.FilterHelper
    .SortList(searchString, typeof(ManageSubscriberItems), models);

if(models.Any())

它会抛出这个错误:

"LINQ to Entities 无法识别方法 'System.String ToString()' 方法,并且这个方法不能翻译成store 表达。”


编辑

我找到了问题,但我仍然无法解决它。所以如果属性不是string,调用.ToString().Contains()时会抛出错误。

model = model.Where(propertyName + " != NULL AND " + propertyName + 
    ".ToString().Contains(@0)", value);

我想要的是在查询中实现LIKE。谁能帮帮我?

【问题讨论】:

  • 看看docs.microsoft.com/en-us/dotnet/api/…,我认为你不能在 LinQ 或 EF 中使用 ToString()。您可以做的是在查询之前创建一个属性/变量并设置其值 .ToString(),而不是使用该属性/变量(并删除 .ToString())。类似的东西:c-sharpcorner.com/blogs/…
  • 这是 LINQ to SQL 还是 LINQ to EF? ToString 似乎在 LINQ to SQL 中静态或动态地为我工作。
  • 如果类型是数字,你可以试试SqlFunctions.StringConvert。
  • @NetMage 这是IQueryable 形式的 Linq to SQL。如果我先调用ToList() 或ToEnumerable() 可能会起作用,但我不想在内存中处理它。我尝试在动态表达式(以字符串形式编写)中使用SqlFunctions.StringConvert,但它给了我一个错误。现在我只能检查它是否是数字,我使用==,如果是字符串我使用.Contains()。这不是我想要的。它的行为不像 Like 运算符。
  • 您使用的是 EF 的哪个版本?

标签: c# sql-server linq dynamic dynamic-linq


【解决方案1】:

如果您将 System.Linq.Dynamic.Core 与 EF Core 一起使用,您可以选择使用

var q = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");

有关示例,请参见此链接: https://github.com/StefH/System.Linq.Dynamic.Core/blob/6fc7fcc43b248940560a0728c4d181e191f9eec1/src-console/ConsoleAppEF2.1.1/Program.cs#L117

我刚刚在连接真实数据库的 linqpad 中进行了测试,这样的代码可以正常工作吗?

var result1 = Entity1s.Where("Url != NULL AND it.Url.Contains(@0)", "e");


[更新 2019-04-17]]

如果您不知道类型,可以将其转换为 object,然后将其转换为 string。

代码:

var r = Entity1s.Select("string(object(Rating))").Where("Contains(@0)", "6");

【讨论】:

  • 我没有使用 EF Core。 Contains() 只能由字符串类型对象使用,否则会引发错误。
【解决方案2】:

所以这里的问题是 IQueryable 事情发生在 SQL 服务器上而不是 C#...所以 SQL 服务器不知道关于 .toString() 方法的任何信息。 所以 => 和 Like 运算符 它自己适用于字符串.. 所以它是 SQL Server 中的 nvarchar 和 varchar 数据类型。 如果你能告诉我更多关于你的问题和你想要达到的目标,我可以给你一个如何实现它的例子。 可以做一个样品。

【讨论】:

    【解决方案3】:

    你已经在 Linq 中有一个“Like”,它可以在数据库中运行并使用字符串,它被称为“IndexOf”:

     ((IQueryable)model).Where(m => m.Property.IndexOf(searchString) == 1);
    

    根据 MSDN: IndexOf(string)

    '如果找到该字符串,则 value 的从零开始的索引位置,否则为 -1。如果值为 Empty,则返回值为 0。'

    【讨论】:

      【解决方案4】:

      所以我想为我的数据做一个通用的排序器。

      而不是修复'invoke issue',一般的方式应该使用泛型,比如

      public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, 
                                             string property,
                                             bool asc = true) where T : class
      {
          //STEP 1: Validate MORE!
          var searchProperty = typeof(T).GetProperty(property);
          if (searchProperty == null) throw new ArgumentException("property");
      
           ....
      
          //STEP 2: Create the OrderBy property selector
          var parameter = Expression.Parameter(typeof(T), "o");
          var selectorExpr = Expression.Lambda(Expression.Property(parameter, property), parameter)        
      
          //STEP 3: Update the IQueryable expression to include OrderBy
          Expression queryExpr = source.Expression;
          queryExpr = Expression.Call(typeof(Queryable), asc ? "OrderBy" : "OrderByDescending",
                                        new Type[] { source.ElementType, searchProperty.PropertyType },
                                       queryExpr, 
                                      selectorExpr);
      
          return source.Provider.CreateQuery<T>(queryExpr);
      }
      

      具有属性名称字符串和方向,通常用于对数据进行“列排序”。

      接下来是关系谓词,'Linq.Dynamic' 从头开始​​似乎是合理的,但有通用和规范的形式exists。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 1970-01-01
        • 2010-11-03
        • 2013-11-25
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多