ODP.Net 托管驱动程序 - ORA-12704:生成的代码中的字符集不匹配
ODP.Net Managed Driver - ORA-12704: character set mismatch in generated code
我目前正在使用 Oracle Managed Driver (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''
。由于列不是 unicode,如果我删除前面的 N
只留下 ''
,那么 sql 将按预期工作。
有什么办法可以防止这种违约吗?
所有数据库列目前都是 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
的拦截器 class NVarcharInterceptor
,并覆盖了所有 ..Executing(..)
方法以包含以下代码:
if (command != null && !string.IsNullOrWhiteSpace(command.CommandText))
command.CommandText = command.CommandText.Replace("N''", "''");
这有效地从我的 DbContext
上执行的任何命令中删除了任何不需要的 NVarchar
引用。
为了添加拦截器,我在DBConfiguration
class中添加了以下代码:
this.AddInterceptor(new NVarcharInterceptor());
您还可以为字符串连接创建自定义函数,并在 LINQ 中调用它,而不是直接进行字符串连接。
例如:
创建数据库函数。
create or replace FUNCTION CONCAT2
(
PARAM1 IN VARCHAR2
, PARAM2 IN VARCHAR2
) RETURN VARCHAR2 AS
BEGIN
RETURN PARAM1 || PARAM2;
END CONCAT2;
将它添加到您的 model.I 使用数据库优先方法,所以我只需要更新模型。
代码中的地图功能:
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})
当我在 IQueryable 上使用字符串连接时,在 select 子句上使用 Lambda 表达式有相同的症状。
然后我只在第一个select上暴露了所有deisred字段,然后将其转换为List,最后在转换后进行拼接。然后错误消失了
该应用程序将 EF 4 与 Oracle.DataAcces 一起使用,而我迁移到带有 ManagedDataAccess 的 EF6,因此我必须对我的代码进行重构。
我目前正在使用 Oracle Managed Driver (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''
。由于列不是 unicode,如果我删除前面的 N
只留下 ''
,那么 sql 将按预期工作。
有什么办法可以防止这种违约吗?
所有数据库列目前都是 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
的拦截器 class NVarcharInterceptor
,并覆盖了所有 ..Executing(..)
方法以包含以下代码:
if (command != null && !string.IsNullOrWhiteSpace(command.CommandText))
command.CommandText = command.CommandText.Replace("N''", "''");
这有效地从我的 DbContext
上执行的任何命令中删除了任何不需要的 NVarchar
引用。
为了添加拦截器,我在DBConfiguration
class中添加了以下代码:
this.AddInterceptor(new NVarcharInterceptor());
您还可以为字符串连接创建自定义函数,并在 LINQ 中调用它,而不是直接进行字符串连接。
例如: 创建数据库函数。
create or replace FUNCTION CONCAT2
(
PARAM1 IN VARCHAR2
, PARAM2 IN VARCHAR2
) RETURN VARCHAR2 AS
BEGIN
RETURN PARAM1 || PARAM2;
END CONCAT2;
将它添加到您的 model.I 使用数据库优先方法,所以我只需要更新模型。 代码中的地图功能:
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})
当我在 IQueryable 上使用字符串连接时,在 select 子句上使用 Lambda 表达式有相同的症状。
然后我只在第一个select上暴露了所有deisred字段,然后将其转换为List,最后在转换后进行拼接。然后错误消失了
该应用程序将 EF 4 与 Oracle.DataAcces 一起使用,而我迁移到带有 ManagedDataAccess 的 EF6,因此我必须对我的代码进行重构。