2012-12-19 10 views
5

Da C#, utilizzando odp.net, chiamo una funzione oracle che restituisce un cursore. Alcune delle colonne sono di tipo "timestamp con fuso orario" (TSTZ). Se utilizzo direttamente un OracleDataAdapter, tali colonne vengono convertite in System.DateTime e le informazioni sul fuso orario vengono perse. Questo è un comportamento previsto e la raccomandazione sembra essere quello di utilizzare SafeMapping per forzare la conversione in stringa del tipo:oracle odp.net Conversione SafeMapping se timestamp con fuso orario - come ottenere offset al posto del nome della zona

dataAdapter.SafeMapping.Add("column_name", typeof(string)); 

Ho poi giunga la TSTZ come una stringa, ma è con il formato DD-MON-YYYY HH:MI:SS.FF AM TZR in questo modo:

23-NOV-12 08.10.12.057868000 PM ASIA/CALCUTTA 

Quello che voglio invece l'offset (ad esempio formato DD-MON-YYYY HH:MI:SS.FF AM TZH:TZD come:

23-NOV-12 08.10.12.057868000 PM +04:30 

Quando ho query di Oracle direttamente (diciamo in S ql Developer), posso usare

Alter Session Set Nls_Timestamp_Tz_Format='DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM' 

per ottenere il formato desiderato. Uso odp.net ho provato sia modificando il formato in SetSessionInfo:

connection.Open(); 
OracleGlobalization glob = connection.GetSessionInfo(); 
glob.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM"; 
connection.SetSessionInfo(glob); 

nonché eseguire il comando alter session utilizzando la stessa connessione, ma non ha alcun effetto. Presumo questo perché la conversione in stringa avviene in una fase successiva e le impostazioni di connessione non hanno alcun effetto.

C'è qualche altro modo per avere Odp.net fornirmi l'offset direttamente? Non riesco a modificare la funzione db di Oracle, quindi l'utilizzo di tz_offset nel metodo non è un'opzione.

Se ciò non è possibile, qual è il modo migliore per convertire la stringa del fuso orario in offset? Attualmente sto pensando di esecuzione di un

select TZNAME, TZABBREV, tz_offset(TZNAME) as TZOFFSET 
from V$TIMEZONE_NAMES 

una volta per costruire un LOOKUPTABLE, ma sarei felice se ci sono opzioni migliori.

Il mio codice di recupero dei dati, comprese le cose che ho provato:

using (var connection = new OracleConnection(this.connectionString)) 
{ 
connection.Open(); 
OracleGlobalization glob = connection.GetSessionInfo(); 
glob.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM"; 
connection.SetSessionInfo(glob); 
string sql = "ALTER SESSION " + 
"SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"'"; 

using (var cmd = connection.CreateCommand()) 
{ 
    cmd.CommandText = sql; 
    cmd.ExecuteNonQuery(); 
}  

using (var cmd = connection.CreateCommand()) 
{ 
    cmd.CommandText = "fn_name"; 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.BindByName = false; 
    var output = cmd.Parameters.Add("return_value", OracleDbType.RefCursor); 
    output.Direction = ParameterDirection.ReturnValue; 
    cmd.Parameters.Add("id", id).Direction = ParameterDirection.Input; 

    using (var dataAdapter = new OracleDataAdapter(cmd)) 
    { 

     dataAdapter.SafeMapping.Add("TZ_COLUMN", typeof(string)); 
     dataAdapter.TableMappings.Add("Table", "Table"); 
     OracleGlobalization glob2 = connection.GetSessionInfo(); 
     glob2.TimeStampTZFormat = "DD-MON-YYYY HH:MI:SS.FF AM TZH:TZM"; 
     connection.SetSessionInfo(glob2); 
     dataAdapter.Fill(dataSet); 
    } 
    foreach (DataRow row in dataSet.Tables[0].Rows) 
    { 
    // column is string with timezone name, I want offset 
    } 
    } 

Grazie

+0

Scartare implicitamente le informazioni sul fuso orario suona più come un errore piuttosto che come un comportamento previsto per me. Dato che non ho familiarità con OPD.NET il seguente è un'ipotesi, ma potresti probabilmente avvolgere la chiamata di funzione in un'altra stored procedure che inoltra la chiamata alla funzione originale. Il wrapper (che viene eseguito sul database prima della conversione del tipo) potrebbe estrarre il fuso orario e riportarlo come colonna aggiuntiva. –

+0

Grazie, ma purtroppo non posso cambiare il metodo. Tuttavia, ho appena capito cosa sembra un modo molto semplice per rendere il DataAdapter restituire tipi specifici di Oracle. –

risposta

2

Sembra una soluzione molto semplice è quella di impostare

dataAdapter.ReturnProviderSpecificTypes = true; 

questo sembra consistere ODP.net non esegue il converstion lossy NET System.DateTime ma invece utilizzare esso la propria datetypes.

1

Forse il seguente link può aiutare?

http://docs.oracle.com/html/A96160_01/oratyp10.htm#1130922

Questo racconta di tipo OracleTimeStampTZ in grado di memorizzare le informazioni di fuso orario anche. La proprietà del fuso orario restituisce informazioni sul fuso orario.

+0

Grazie. Il problema era che non sapevo come rendere ODP.net restituire questo invece di DateTime (default) o string/byte [] (usando la funzione safemapping) –

Problemi correlati