实体框架核心:包含土耳其语字符



技术

无法更改排序规则为Turkish_CI_AS的共享服务器上的SQL Server 2014。
  • 实体框架核心5.0.5

  • 数据库中的数据:

    1: MILK THISTLE
    2: CLEANSING MILK
    3: MILKA CHOCOLATE
    

    查询:

    Products.Where(p => p.Name.Contains("MILK")) // outputs all records
    Products.Where(p => p.Name.Contains("milk")) // does not output anything
    Products.Where(p => p.Name.Contains("mılk")) // notice the turkish letter ı, outputs all records
    

    所需行为:搜索字符串中的"或";牛奶";或";mılk";或";"牛奶";或";MíLK";应输出所有三行。

    我尝试使用:

    • .ToUpper().ToLower()//所有你能想到的组合。。与上面使用的术语相同
    • EF.Functions.Like//运行但没有结果
    • StringComparison.InvariantCultureIgnoreCase//抛出错误
    • EF.Functions.Collate(c.Name, "SQL_Latin1_General_CP1_CS_AS")//也尝试使用Turkish_CI_AS运行与上面使用的术语相同的术语

    救命!


    编辑-2021-06-08

    问题似乎不仅仅和土耳其文字有关。例如,此查询:

    Products.Where(p => p.Name.ToLower().Contains("SENSITIVE"))
    

    输出10个乘积;灵敏的";在他们的名字里。然而,这个查询:

    Products.Where(p => p.Name.ToLower().Contains("sensitive"))
    

    没有输出结果!

    这些查询的原始SQL字符串为:

    SELECT TOP(@__p_0) [p].[ProductId], [p].[BrandId], [p].[CampaignDisctountAmount], [p].[CampaignMFValue], [p].[Code], [p].[DefaultPicturePath], [p].[Description], [p].[GroupId], [p].[HowToUse], [p].[Ingredients], [p].[InventoryQuantity], [p].[IsDiscontinued], [p].[IsDisplayStockQty], [p].[IsDisplayedOnCatalog], [p].[LogoId], [p].[Name], [p].[Price1], [p].[Price2], [p].[Slug], [p].[Status], [p].[Summary], [p].[Unit], [p].[UnitValue], [p].[VatPercent], [p].[Warnings]
    FROM [MED].[Products] AS [p]
    WHERE LOWER([p].[Name]) LIKE N'%SENSITIVE%'
    

    我在SQL Server Management Studio中运行了这两个SQL字符串,并确认我确实没有用单词"得到任何结果;敏感的";但所有匹配的记录都在"0"时返回;灵敏的";使用。

    所有的名字都用大写字母存储在我的数据库中。数据库和表排序规则都是Turkish_CI_AS,我无法更改它,因为我在共享服务器上。

    这个问题是由于使用服务器端排序规则在服务器上进行比较而导致的,并且您无法通过EF的linq提供程序来更改这一点(这就是StringComparison参数重载失败的原因(。排序规则不区分大小写,但当然,作为土耳其语,'i'和"I"是不同的字符。

    解决方案是停止尝试更改数据库中产品名称的大小写,而是修改搜索条件

    由于所搜索的数据都不包含'İ',因此修改很简单:对搜索值调用ToUpper(),并确保转换不使用土耳其文化例如,如果客户端上的默认区域性不是土耳其语,则可以使用

    Products.Where(p => p.Name.Contains("sensitive".ToUpper()))
    

    如果客户端是土耳其语,则使用ToUpper()的重载,该重载采用CultureInfo参数:

    Products.Where(p => p.Name.Contains("sensitive".ToUpper(CultureInfo.InvariantCulture)))
    

    仔细想想,linq提供者实际上可能仍然在服务器上进行转换;如果是这种情况,那么您可以在表达式lambda:之外进行转换

    var criterion = "sensitive".ToUpper(CultureInfo.InvariantCulture);
    return Products.Where(p => p.Name.Contains(criterion));
    

    我今天面对并处理了这个问题。我的数据库是postgreSql,我有一些土耳其数据。其他土耳其语字符,如"ş"、"ç"、"ö"、"ü"one_answers"ğ"或它们的大写版本没有问题。

    问题出在";";以及字母";ı";。这些字母可以在数据库数据中,也可以在searchModel数据中。

    在这种情况下,我将字母";";以及字母";ı";变成字母";i";。像这样:

    var lowerStr = AnyWordThatContainsTrCharacters.ToLower().Replace("İ", "i").Replace("ı", "i");
    return Product.Where(p => p.Name.ToLower().Replace("İ", "i").Replace("ı", "i").Contains(lowerStr));
    

    最新更新