Driver gerenciado ODP.Net – ORA-12704: incompatibilidade de conjunto de caracteres no código gerado

No momento, estou usando o driver gerenciado do Oracle (v12.1.2400) como meu driver do Entity Framework e estou vendo atualmente um erro de ORA-12704: character set mismatch durante a execução.

O código LINQ-> SQL que estou usando é o seguinte:

 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}) 

e isso está criando o seguinte 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; 

Quando eu depurar esse SQL, posso ver que o problema é que o SQL está usando N'' nas seções CASE . Como as colunas não são unicode, se eu remover o N anterior para deixar apenas '' então o sql funciona como esperado.

Existe alguma maneira de evitar esse padrão?

Todas as colunas de db são atualmente VARCHAR e são modeladas em C # como string .
Os primeiros mapeamentos de código para as duas colunas são os seguintes:

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

Eu estava esperando que a IsUnicode(false) cuidaria disso.

FYI, isso costumava funcionar quando eu usava o EF5 e o driver não gerenciado.
Além disso, os drivers de dotConnectForOracle do Devart não têm esse problema, então estou pensando que isso é um bug nos drivers do Oracle.

Eu nunca encontrei a solução adequada para isso, no entanto eu encontrei uma solução que funciona bem.

Eu criei uma class Interceptor NVarcharInterceptor implementando IDbCommandInterceptor e ..Executing(..) todos os ..Executing(..) para conter o seguinte código:

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

Isso efetivamente remove qualquer uma das referências indesejadas do NVarchar , de qualquer comando que está sendo executado no meu DbContext .

Para adicionar o interceptor, adicionei o seguinte código à class DBConfiguration :

 this.AddInterceptor(new NVarcharInterceptor()); 

Além disso, você pode criar uma function personalizada para a concatenação de strings e chamá-la no LINQ em vez de uma concatenação direta de string.

Por exemplo: crie uma function de database.

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

Adicioná-lo ao seu modelo.Eu uso o primeiro database abordagem, então eu só tive que atualizar o modelo. Mapear function no código:

 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); } } 

E use-o em suas consultas 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})