2
2
using System . Collections . Generic ;
3
3
using System . Data ;
4
4
using System . Data . Common ;
5
- using System . Globalization ;
6
5
using System . Linq ;
7
6
using System . Linq . Expressions ;
8
7
using System . Reflection ;
9
8
using System . Text ;
10
9
using System . Text . RegularExpressions ;
11
- using System . Threading ;
12
10
13
11
namespace ServiceStack . OrmLite . Oracle
14
12
{
@@ -127,6 +125,9 @@ public override string ToPostCreateTableStatement(ModelDefinition modelDef)
127
125
return null ;
128
126
}
129
127
128
+ private OracleTimestampConverter _timestampConverter ;
129
+ private readonly object _timestampLock = new object ( ) ;
130
+
130
131
public override IDbConnection CreateConnection ( string connectionString , Dictionary < string , string > options )
131
132
{
132
133
if ( options != null )
@@ -135,7 +136,11 @@ public override IDbConnection CreateConnection(string connectionString, Dictiona
135
136
}
136
137
137
138
var factory = DbProviderFactories . GetFactory ( ClientProvider ) ;
138
- InitializeOracleTimestampSetting ( factory ) ;
139
+ lock ( _timestampLock )
140
+ {
141
+ if ( _timestampConverter == null )
142
+ _timestampConverter = new OracleTimestampConverter ( factory ) ;
143
+ }
139
144
IDbConnection connection = factory . CreateConnection ( ) ;
140
145
if ( connection != null ) connection . ConnectionString = connectionString ;
141
146
return connection ;
@@ -159,8 +164,8 @@ public override void SetDbValue(FieldDefinition fieldDef, IDataReader reader, in
159
164
object convertedValue ;
160
165
if ( fieldDef . FieldType == typeof ( DateTimeOffset ) )
161
166
{
162
- SetOracleTimestampTzFormat ( ) ;
163
- convertedValue = ConvertTimestampTzToDateTimeOffset ( reader , colIndex ) ;
167
+ _timestampConverter . SetOracleTimestampTzFormat ( ) ;
168
+ convertedValue = _timestampConverter . ConvertTimestampTzToDateTimeOffset ( reader , colIndex ) ;
164
169
}
165
170
else
166
171
{
@@ -392,7 +397,7 @@ public override void SetParameterValue<T>(FieldDefinition fieldDef, IDataParamet
392
397
393
398
if ( fieldDef . ColumnType == typeof ( DateTimeOffset ) || fieldDef . ColumnType == typeof ( DateTimeOffset ? ) )
394
399
{
395
- SetOracleParameterTypeTimestampTz ( p ) ;
400
+ _timestampConverter . SetOracleParameterTypeTimestampTz ( p ) ;
396
401
}
397
402
p . Value = value ;
398
403
}
@@ -411,101 +416,14 @@ protected override object GetValue<T>(FieldDefinition fieldDef, object obj)
411
416
}
412
417
if ( fieldDef . FieldType == typeof ( DateTimeOffset ) )
413
418
{
414
- SetOracleTimestampTzFormat ( ) ;
419
+ _timestampConverter . SetOracleTimestampTzFormat ( ) ;
415
420
var timestamp = ( DateTimeOffset ) value ;
416
- return timestamp . ToString ( DateTimeOffsetOutputFormat , CultureInfo . InvariantCulture ) ;
421
+ return _timestampConverter . ConvertDateTimeOffsetToString ( timestamp ) ;
417
422
}
418
423
}
419
424
return value ;
420
425
}
421
426
422
- private string DateTimeOffsetOutputFormat { get ; set ; }
423
- private string DateTimeOffsetInputFormat { get ; set ; }
424
- private string TimestampTzFormat { get ; set ; }
425
- private readonly Dictionary < int , bool > _threadFormatSet = new Dictionary < int , bool > ( ) ;
426
- private const BindingFlags InvokeStaticPublic = BindingFlags . Public | BindingFlags . Static | BindingFlags . InvokeMethod ;
427
- private Assembly OracleAssembly { get ; set ; }
428
- private object ClientInfo { get ; set ; }
429
- private MethodInfo SetThreadInfo { get ; set ; }
430
- private MethodInfo SetOracleDbType { get ; set ; }
431
- private object TimestampTz { get ; set ; }
432
- private MethodInfo GetOracleValue { get ; set ; }
433
-
434
- private void InitializeOracleTimestampSetting ( DbProviderFactory factory )
435
- {
436
- OracleAssembly = factory . GetType ( ) . Assembly ;
437
- var globalizationType = OracleAssembly . GetType ( "Oracle.DataAccess.Client.OracleGlobalization" ) ;
438
- if ( globalizationType != null )
439
- {
440
- DateTimeOffsetInputFormat = DateTimeOffsetOutputFormat = "yyyy-MM-dd HH:mm:ss.ffffff zzz" ;
441
- TimestampTzFormat = "YYYY-MM-DD HH24:MI:SS.FF6 TZH:TZM" ;
442
-
443
- ClientInfo = globalizationType . InvokeMember ( "GetClientInfo" , InvokeStaticPublic , null , null , null ) ;
444
- const BindingFlags setProperty = BindingFlags . Public | BindingFlags . SetProperty | BindingFlags . Instance ;
445
- globalizationType . InvokeMember ( "TimeStampTZFormat" , setProperty , null , ClientInfo , new object [ ] { TimestampTzFormat } ) ;
446
- SetThreadInfo = globalizationType . GetMethod ( "SetThreadInfo" , BindingFlags . Public | BindingFlags . Static ) ;
447
-
448
- var parameterType = OracleAssembly . GetType ( "Oracle.DataAccess.Client.OracleParameter" ) ;
449
- var oracleDbTypeProperty = parameterType . GetProperty ( "OracleDbType" , BindingFlags . Public | BindingFlags . Instance ) ;
450
- SetOracleDbType = oracleDbTypeProperty . GetSetMethod ( ) ;
451
-
452
- var oracleDbType = OracleAssembly . GetType ( "Oracle.DataAccess.Client.OracleDbType" ) ;
453
- TimestampTz = Enum . Parse ( oracleDbType , "TimeStampTZ" ) ;
454
-
455
- var readerType = OracleAssembly . GetType ( "Oracle.DataAccess.Client.OracleDataReader" ) ;
456
- GetOracleValue = readerType . GetMethod ( "GetOracleValue" , BindingFlags . Public | BindingFlags . Instance ) ;
457
- }
458
- else
459
- {
460
- //TODO This is Microsoft provider support and it does not handle the offsets correctly,
461
- // but I don't know how to make it work.
462
-
463
- DateTimeOffsetOutputFormat = "dd-MMM-yy hh:mm:ss.fff tt" ;
464
- DateTimeOffsetInputFormat = "dd-MMM-yy hh:mm:ss tt" ;
465
- TimestampTzFormat = "DD-MON-RR HH.MI.SSXFF AM" ;
466
-
467
- // var parameterType = OracleAssembly.GetType("System.Data.OracleClient.OracleParameter");
468
- // var oracleTypeProperty = parameterType.GetProperty("OracleType", BindingFlags.Public | BindingFlags.Instance);
469
- // SetOracleDbType = oracleTypeProperty.GetSetMethod();
470
-
471
- var oracleDbType = OracleAssembly . GetType ( "System.Data.OracleClient.OracleType" ) ;
472
- TimestampTz = Enum . Parse ( oracleDbType , "TimestampWithTZ" ) ;
473
-
474
- // var readerType = OracleAssembly.GetType("System.Data.OracleClient.OracleDataReader");
475
- // GetOracleValue = readerType.GetMethod("GetOracleValue", BindingFlags.Public | BindingFlags.Instance);
476
- }
477
- }
478
-
479
- private void SetOracleTimestampTzFormat ( )
480
- {
481
- if ( ClientInfo == null ) return ;
482
-
483
- var threadId = Thread . CurrentThread . ManagedThreadId ;
484
- if ( _threadFormatSet . ContainsKey ( threadId ) ) return ;
485
-
486
- SetThreadInfo . Invoke ( null , new [ ] { ClientInfo } ) ;
487
- _threadFormatSet [ threadId ] = true ;
488
- }
489
-
490
- private void SetOracleParameterTypeTimestampTz ( IDataParameter p )
491
- {
492
- if ( SetOracleDbType != null ) SetOracleDbType . Invoke ( p , new [ ] { TimestampTz } ) ;
493
- }
494
-
495
- private DateTimeOffset ConvertTimestampTzToDateTimeOffset ( IDataReader dataReader , int colIndex )
496
- {
497
- if ( GetOracleValue != null )
498
- {
499
- var value = GetOracleValue . Invoke ( dataReader , new object [ ] { colIndex } ) . ToString ( ) ;
500
- return DateTimeOffset . ParseExact ( value , DateTimeOffsetInputFormat , CultureInfo . InvariantCulture ) ;
501
- }
502
- else
503
- {
504
- var value = dataReader . GetValue ( colIndex ) ;
505
- return new DateTimeOffset ( ( DateTime ) value ) ;
506
- }
507
- }
508
-
509
427
public override string ToInsertRowStatement ( IDbCommand dbCommand , object objWithProperties , ICollection < string > insertFields = null )
510
428
{
511
429
if ( insertFields == null )
@@ -797,7 +715,7 @@ public override List<string> ToCreateIndexStatements(Type tableType)
797
715
indexName = NamingStrategy . ApplyNameRestrictions ( indexName ) ;
798
716
799
717
sqlIndexes . Add (
800
- ToCreateIndexStatement ( fieldDef . IsUnique , indexName , modelDef , fieldDef . FieldName , false ) ) ;
718
+ ToCreateIndexStatement ( fieldDef . IsUnique , indexName , modelDef , fieldDef . FieldName ) ) ;
801
719
}
802
720
803
721
foreach ( var compositeIndex in modelDef . CompositeIndexes )
@@ -807,7 +725,7 @@ public override List<string> ToCreateIndexStatements(Type tableType)
807
725
var indexNames = string . Join ( "," , compositeIndex . FieldNames . ToArray ( ) ) ;
808
726
809
727
sqlIndexes . Add (
810
- ToCreateIndexStatement ( compositeIndex . Unique , indexName , modelDef , indexNames , false ) ) ;
728
+ ToCreateIndexStatement ( compositeIndex . Unique , indexName , modelDef , indexNames ) ) ;
811
729
}
812
730
813
731
return sqlIndexes ;
0 commit comments