【问题标题】:Entity Framework Code First String Comparison with Oracle Db实体框架代码优先字符串与 Oracle Db 的比较
【发布时间】:2014-09-02 04:04:04
【问题描述】:

我在使用代码首先针对 Oracle 数据库进行不区分大小写的字符串比较时遇到问题。代码看起来像这样;

String filter = "Ali";
var employee = dbContext.Employees.Where(x => x.Name.Contains(filter)).FirstOrDefault();

上面的代码是区分大小写的。所以我将名称和过滤器都转换为大写;

String filter = "Ali";
filter = filter.ToUpper();
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filter)).FirstOrDefault();

一开始似乎一切正常,但后来我意识到当员工姓名或过滤器包含字符“i”时它不起作用。问题是字母 i 在土耳其语中的工作方式。

在大多数语言中,“i”代表小写,“I”代表字符的大写。但是在土耳其语中,'i 的大写字母是 'İ',而 'I 的小写字母是 'ı'。这是一个问题,因为 Oracle 将 db 中的字母“i”大写为“I”。

我们无法访问数据库的字符编码设置,因为它的影响无法轻易预见。

我想出的是这个,而且很丑。

String filterInvariant = filter.ToUpper(CultureInfo.InvariantCulture);
String filterTurkish = filter.ToUpper(CultureInfo.CreateSpecificCulture("tr-TR"));
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filterInvariant) || x.Name.ToUpper().Contains(filterTurkish)).FirstOrDefault();

它似乎解决了一些问题,但感觉像是一种蛮力解决方法,而不是一个可靠的解决方案。在针对 Oracle 数据库使用 Code First C# 时,此解决方法的最佳做法或替代方法是什么?

提前致谢

【问题讨论】:

    标签: c# oracle linq ef-code-first string-comparison


    【解决方案1】:

    String.Contains 的实现对于不同的提供者是不同的,例如 Linq2Sql 总是不区分大小写的。搜索是否区分大小写取决于server settings。例如,默认情况下 SQL Server 具有 SQL_Latin1_General_CP1_CI_AS 排序规则,并且不区分大小写。对于 Oracle,您可以在会话级别更改此行为:Case insensitive searching in Oracle(在会话开始时使用 context.Database.ExecuteSqlCommand 方法发出原始 SQL 查询)

    【讨论】:

      【解决方案2】:

      问题出在数据库,不在.NET,例如这个查询:

      FILES.Where(t => t.FILE_NAME.ToUpper() == "FILE.TXT") // Get rows from file-table
      

      使用我拥有的 oracle 提供程序翻译成这个 Oracle SQL:

      SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
      FROM FILES t0
      WHERE (UPPER(t0.FILE_NAME) = :p0)
      -- p0 = [FILE.TXT]
      

      First() 的包含变成这样:

      SELECT * FROM (SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
                  FROM FILES t0
                  WHERE ((UPPER(t0.FILE_NAME) LIKE '%' || :p0 || '%') 
                      OR (UPPER(t0.FILE_NAME) LIKE '%' || :p1 || '%'))) 
      WHERE ROWNUM<=1
      -- p0 = [FILE.TXT]
      -- p1 = [FİLE.TXT]
      

      所以这取决于您的数据库的文化设置,即在不知道它们的情况下,我会说与您的解决方案“重叠”是解决它的最佳方法。为什么不能只检查数据库文化设置?

      【讨论】:

        【解决方案3】:

        使用所有UPPER 函数。只需让 Oracle 进行语言感知的不区分大小写匹配即可。这是通过将您的数据库连接从 C# 设置为具有适当的语言参数来完成的。此设置仅适用于您的数据库会话,而不是整个数据库的全局更改。我不是 C# 向导,所以你必须弄清楚在你的数据库连接/池代码中进行这些会话设置的位置。

        ALTER SESSION SET nls_language=TURKISH;
        ALTER SESSION SET nls_comp=LINGUISTIC;
        ALTER SESSION SET nls_sort=BINARY_CI;
        

        如果 C# 证明太难找到在哪里更改它,您可以将其设置为用户/模式登录触发器(如下),它会在 db 连接时自动为您设置这些(将 SOMEUSER 替换为您的实际 db用户名)。这只会影响任何新的数据库会话,因此如果您有连接池,您需要循环数据库连接池以刷新连接。

        CREATE OR REPLACE TRIGGER SOMEUSER.SET_NLS_CASE_INSENSITIVE_TRG AFTER
                           LOGON ON SOMEUSER.SCHEMA
          BEGIN
            EXECUTE IMMEDIATE 'ALTER SESSION SET nls_language=TURKISH';
            EXECUTE IMMEDIATE 'ALTER SESSION SET nls_comp=LINGUISTIC';
            EXECUTE IMMEDIATE 'ALTER SESSION SET nls_sort=BINARY_CI';
          END;
        /
        

        这是我在 Oracle DB 中进行的一个小测试:

        CREATE TABLE mypeople (name VARCHAR2(10 CHAR));
        
        INSERT INTO mypeople VALUES ('Alİ Hassan');
        INSERT INTO mypeople VALUES ('AlI Hassan');
        INSERT INTO mypeople VALUES ('Ali Hassan');
        INSERT INTO mypeople VALUES ('Alı Hassan');
        
        SELECT name FROM mypeople WHERE name LIKE 'Ali%';
        
        NAME
        ----------
        Ali Hassan
        
        ALTER SESSION SET nls_language=TURKISH;
        ALTER SESSION SET nls_comp=LINGUISTIC;
        ALTER SESSION SET nls_sort=BINARY_CI;
        
        SELECT name FROM mypeople WHERE name LIKE 'Ali%';
        
        NAME
        ----------
        Alİ Hassan
        AlI Hassan
        Ali Hassan
        

        【讨论】:

        • 感谢 Joshua 非常详细的回复,这既有益又有益。
        • 嗯,很高兴为您提供帮助。 Ps,我在追你的赏金。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-05
        相关资源
        最近更新 更多