ODP.Net托管驱动程序 – ORA-12704:生成的代码中的字符集不匹配

我目前正在使用Oracle托管驱动程序(v12.1.2400)作为我的entity framework驱动程序,并且我目前在执行期间看到ORA-12704: character set mismatch错误。

我使用的LINQ-> SQL代码如下:

 from c in CUSTOMER.AsNoTracking() where c.ACCOUNT.Contains("DE") && c.DELETED == "N" orderby (c.FORENAME + c.SURNAME) select new { c.ACCOUNT, c.FORENAME, c.SURNAME}) 

这是创建以下SQL:

 SELECT "Project1"."C2" AS "C1", "Project1"."ACCOUNT" AS "ACCOUNT", "Project1"."FORENAME" AS "FORENAME", "Project1"."SURNAME" AS "SURNAME" FROM ( SELECT( (CASE WHEN ("Extent1"."FORENAME" IS NULL) THEN N'' ELSE "Extent1"."FORENAME" END) ||(CASE WHEN ("Extent1"."SURNAME" IS NULL) THEN N'' ELSE "Extent1"."SURNAME" END)) AS "C1", "Extent1"."ACCOUNT" AS "ACCOUNT", "Extent1"."FORENAME" AS "FORENAME", "Extent1"."SURNAME" AS "SURNAME", 1 AS "C2" FROM "TEST"."CUSTOMER" "Extent1" WHERE (("Extent1"."ACCOUNT" LIKE '%DE%') AND ('N' = "Extent1"."DELETED"))) "Project1" ORDER BY "Project1"."C1" ASC; 

当我调试该SQL时,我可以看到问题是SQL在CASE部分中使用N'' 。 AS teh列不是unicode,如果我删除前面的N只留下''然后sql按预期工作。

有什么办法可以防止这种违约吗?

所有db列当前都是VARCHAR ,并以C#格式化为string
两列的代码优先映射如下:

 this.Property(t => t.FORENAME).HasColumnName("FORENAME").IsUnicode(false).HasMaxLength(35); this.Property(t => t.SURNAME).HasColumnName("SURNAME").IsUnicode(false).HasMaxLength(35); 

我原以为IsUnicode(false)声明会解决这个问题。

仅供我在使用EF5和非托管驱动程序时使用。
另外,Devart dotConnectForOracle驱动程序没有这个问题,所以我认为这是Oracle驱动程序中的一个错误。

我从来没有找到适当的解决方案,但我找到了一个运作良好的解决方法。

我创建了一个实现IDbCommandInterceptor的Interceptor类NVarcharInterceptor ,并覆盖所有..Executing(..)方法以包含以下代码:

 if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) command.CommandText = command.CommandText.Replace("N''", "''"); 

这有效地从我的DbContext上执行的任何命令中删除任何不需要的NVarchar引用。

要添加拦截器,我在DBConfiguration类中添加了以下代码:

 this.AddInterceptor(new NVarcharInterceptor()); 

您还可以为字符串连接创建自定义函数,并在LINQ中调用它而不是直接字符串连接。

例如:创建数据库function。

 create or replace FUNCTION CONCAT2 ( PARAM1 IN VARCHAR2 , PARAM2 IN VARCHAR2 ) RETURN VARCHAR2 AS BEGIN RETURN PARAM1 || PARAM2; END CONCAT2; 

将它添加到您的模型。我使用数据库第一种方法,所以我只需要更新模型。 代码中的Map函数:

 using System; using System.Data.Entity; public static class DbFunctions { [DbFunction("Model.Store", "CONCAT2")] public static string Concat(string arg1, string arg2) { return String.Concat(arg1, arg2); } } 

并在您的LINQ查询中使用它:

 from c in CUSTOMER.AsNoTracking() where c.ACCOUNT.Contains("DE") && c.DELETED == "N" orderby DbFunctions.Concat(c.FORENAME, c.SURNAME) select new { c.ACCOUNT, c.FORENAME, c.SURNAME})