2016-01-07 19 views
7

próbuję połączyć kilka kolumn w EF Oracle następnie zrobić .Contains() nad kolumnami tak:EF do rzucania Oracle „ORA-12704: Zestaw znaków niedopasowanie”

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

Jednakże, otrzymuję ten wyjątek:

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

Kolumny, których szukam, są typu VARCHAR2 (128) w Oracle.

Używam tego samego kodu w innym projekcie i to działa. Jedyna różnica polega na tym, że dla projektu, który działa, używam Oracle.DataAccess, a dla tego, który nie działa, używam Oracle.ManagedDataAccess (nie mogę użyć Oracle.DataAccess dla tego projektu). Uważam, że w zarządzanym sterowniku występuje błąd/problem.

Jestem otwarty na rozwiązania lub obejścia.

+0

Jaki znak jest Twoja baza danych używa? Uruchom 'SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET'', aby to ustalić. –

+0

Uruchomiłem to, mówi "WE8MSWIN1252" – solidau

+0

Cóż, to jest sprzeczne z tym, czego się spodziewałem. 'WE8MSWIN1252' to zestaw znaków jednobajtowych, ale IIRC .net używa wewnętrznie kodu Unicode, więc oczekiwałbym, że baza danych lub sterownik powinien móc konwertować z/od jednobajtowego zestawu znaków bazy danych na kod Unicode. Spojrzałem na dokumentację [OracleGlobalization class docs] (http://docs.oracle.com/cd/E51173_01/win.122/e17732/OracleGlobalizationClass.htm#ODPNT3113) i wygląda na to, że żadna z metod nie pozwala na ustawienie zestawu znaków są dostępne w zarządzanym sterowniku. Powodzenia. –

Odpowiedz

14

Skończyło się autor tego (ODP.Net Managed Driver - ORA-12704: character set mismatch in generated code), aby zaktualizować pytanie, on pisał obejścia za pomocą przechwytywania, pójdę nieco więcej szczegółów tutaj ...

pierwsze, zdobione mój DBContext załadować konfigurację. można pominąć to i po prostu dodać do swojej konfiguracji, jeśli masz:

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

utworzyć klasę config:

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

Następnie utwórz przechwytywacza:

zestaw
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

To zadziałało! Świetne obejście! –