实体框架代码与Oracle Db的第一个字符串比较

时间:2014-07-11 13:45:12

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

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

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

上面的代码区分大小写。所以我将Name和filter都转换为大写;

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

一切似乎都在起作用,但后来我意识到当员工的名字或过滤器包含字符'i'时它不起作用。问题是这封信我是如何用土耳其语工作的。

在大多数语言中,'i'代表小写字母,'I'代表字符的大写字母。然而在土耳其语中,“我的大写字母是'İ','我的小写是'ı'。这是一个问题,因为Oracle将数据库中的字母'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#时,最佳实践或此替代方法的替代方法是什么?

提前致谢

3 个答案:

答案 0 :(得分:4)

使用所有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 connect time为您自动设置这些触发器(将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

答案 1 :(得分: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 :(得分:1)

问题出在数据库中,而不是.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]

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