我首先使用代码对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#时,最佳实践或此替代方法的替代方法是什么?
提前致谢
答案 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]
因此,这取决于您的数据库的文化设置,即不知道它们,我会说与您的解决方案“重叠”是解决它的最佳方式。为什么不能只检查数据库文化设置?