2016-01-07 9 views
7

Sto cercando di combinare alcuni colonne EF da Oracle poi fare un .Contains() sulle colonne di questo tipo:EF per Oracle lanciare "ORA-12704: set di caratteri corrispondente"

public IEnumerable<User> SearchUsers(string search) 
{ 
    search = search.ToLower(); 

    return _securityUow.Users 
      .Where(u => (u.FirstName.ToLower() + " " + u.LastName.ToLower() + " (" + u.NetId.ToLower() + ")").Contains(search)) 
      .OrderBy(u => u.LastName) 
      .ThenBy(u => u.FirstName) 
      .AsEnumerable(); 
} 

Tuttavia, sto ottenendo questa eccezione:

{ 
    "Message": "An error has occurred.", 
    "ExceptionMessage": "An error occurred while executing the command definition. See the inner exception for details.", 
    "ExceptionType": "System.Data.Entity.Core.EntityCommandExecutionException", 
    "StackTrace": " at SoftwareRegistration.WebUI.Controllers.Api.V1.UserContactController.Lookup(String search) in C:\LocalRepository\OnlineSupport\SoftwareRegistration\trunk\release\SoftwareRegistration\SoftwareRegistration.WebUI\Controllers\Api\V1\UserContactController.cs:line 40\r\n at lambda_method(Closure , Object , Object[])\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()", 
    "InnerException": { 
    "Message": "An error has occurred.", 
    "ExceptionMessage": "ORA-12704: character set mismatch", 
    "ExceptionType": "Oracle.ManagedDataAccess.Client.OracleException", 
    "StackTrace": " at OracleInternal.ServiceObjects.OracleCommandImpl.VerifyExecution(OracleConnectionImpl connectionImpl, Int32& cursorId, Boolean bThrowArrayBindRelatedErrors, OracleException& exceptionForArrayBindDML, Boolean& hasMoreRowsInDB, Boolean bFirstIterationDone)\r\n at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteReader(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, OracleDataReaderImpl& rdrImpl, Int32 longFetchSize, Int64 clientInitialLOBFS, OracleDependencyImpl orclDependencyImpl, Int64[] scnForExecution, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Int64& internalInitialLOBFS, OracleException& exceptionForArrayBindDML, Boolean isDescribeOnly, Boolean isFromEF)\r\n at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)\r\n at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)\r\n at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)\r\n at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)\r\n at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)\r\n at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)\r\n at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)" 
    } 
} 

Le colonne che sto interrogando sono tutte di tipo VARCHAR2 (128) in Oracle.

Sto anche usando questo stesso identico codice in un altro progetto e funziona. L'unica differenza è che per il progetto che funziona sto usando Oracle.DataAccess e per quello che non funziona, sto usando Oracle.ManagedDataAccess (non sono in grado di utilizzare Oracle.DataAccess per questo progetto). Quindi credo che ci sia un bug/problema nel driver gestito.

Sono aperto a soluzioni o soluzioni alternative.

+0

Che carattere è il tuo database usando? Esegui 'SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET'' per determinarlo. –

+0

l'ho eseguito, si dice 'WE8MSWIN1252' – solidau

+0

Beh, questo è contrario a quello che mi aspettavo. 'WE8MSWIN1252' è un set di caratteri a byte singolo, ma IIRC .net utilizza internamente Unicode quindi mi aspetto che il database o il driver debba essere in grado di convertire da/a dal set di caratteri del database a byte singolo in Unicode. Ho esaminato i [documenti della classe OracleGlobalization] (http://docs.oracle.com/cd/E51173_01/win.122/e17732/OracleGlobalizationClass.htm#ODPNT3113) e sembra che nessuno dei metodi che consentono di impostare il set di caratteri sono disponibili sotto il driver gestito. Buona fortuna. –

risposta

14

Ho finito per ottenere l'autore di questo (ODP.Net Managed Driver - ORA-12704: character set mismatch in generated code) per aggiornare la questione, ha inviato una soluzione utilizzando un intercettore, andrò un po 'più in dettaglio qui ...

In primo luogo, ho decorato la mia DbContext caricare una configurazione. è possibile saltare questa e basta aggiungere alla configurazione se ne hai uno:

[DbConfigurationType(typeof(MyDbConfiguration))] 
public partial class MyContext : DbContext 

creare la classe di configurazione:

public class MyDbConfiguration : DbConfiguration 
{ 
    public MyDbConfiguration() 
    { 
     this.AddInterceptor(new NVarcharInterceptor()); //add this line to existing config. 
    } 
} 

Successivamente, creare l'intercettore:

insieme
public class NVarcharInterceptor : IDbCommandInterceptor 
{ 
    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
     if (command != null && !string.IsNullOrWhiteSpace(command.CommandText)) 
      command.CommandText = command.CommandText.Replace("N''", "''"); 
    } 
} 
+0

Ha funzionato! Ottima soluzione! –