1
+ using System ;
2
+ using System . Data ;
3
+ using System . Data . Common ;
4
+ using System . Reflection ;
5
+ using NHibernate . AdoNet ;
6
+ using NHibernate . Engine . Query ;
7
+ using NHibernate . SqlTypes ;
8
+ using NHibernate . Util ;
9
+
10
+ namespace NHibernate . Driver
11
+ {
12
+ /// <summary>
13
+ /// A NHibernate driver base for using ODP.Net.
14
+ /// </summary>
15
+ /// <remarks>
16
+ /// Original code was contributed by <a href="http://sourceforge.net/users/jemcalgary/">James Mills</a>
17
+ /// on the NHibernate forums in this
18
+ /// <a href="http://sourceforge.net/forum/message.php?msg_id=2952662">post</a>.
19
+ /// </remarks>
20
+ public abstract class OracleDataClientDriverBase : ReflectionBasedDriver , IEmbeddedBatcherFactoryProvider
21
+ {
22
+ private const string _commandClassName = "OracleCommand" ;
23
+
24
+ private const string _unmanagedProviderInvariantName = "Oracle.DataAccess.Client" ;
25
+ private const string _unmanagedDriverAssemblyName = "Oracle.DataAccess" ;
26
+ private const string _unmanagedClientNamespace = "Oracle.DataAccess.Client" ;
27
+
28
+ private const string _managedProviderInvariantName = "Oracle.ManagedDataAccess.Client" ;
29
+ private const string _managedDriverAssemblyName = "Oracle.ManagedDataAccess" ;
30
+ private const string _managedClientNamespace = "Oracle.ManagedDataAccess.Client" ;
31
+
32
+ private static readonly SqlType _guidSqlType = new SqlType ( DbType . Binary , 16 ) ;
33
+ private readonly PropertyInfo _oracleCommandBindByName ;
34
+ private readonly PropertyInfo _oracleDbType ;
35
+ private readonly object _oracleDbTypeRefCursor ;
36
+ private readonly object _oracleDbTypeXmlType ;
37
+
38
+ /// <summary>
39
+ /// Default constructor.
40
+ /// </summary>
41
+ /// <param name="managed"><see langword="true"/> for loading the managed driver, <see langword="false"/> for loading the unmanaged driver.</param>
42
+ /// <exception cref="HibernateException">
43
+ /// Thrown when the <c>Oracle.DataAccess</c> assembly can not be loaded.
44
+ /// </exception>
45
+ protected OracleDataClientDriverBase ( bool managed )
46
+ : this (
47
+ managed ? _managedProviderInvariantName : _unmanagedProviderInvariantName ,
48
+ managed ? _managedDriverAssemblyName : _unmanagedDriverAssemblyName ,
49
+ managed ? _managedClientNamespace : _unmanagedClientNamespace )
50
+ {
51
+ }
52
+
53
+ private OracleDataClientDriverBase ( string providerInvariantName , string driverAssemblyName , string clientNamespace )
54
+ : base ( providerInvariantName , driverAssemblyName , clientNamespace + ".OracleConnection" , clientNamespace + "." + _commandClassName )
55
+ {
56
+ var oracleCommandType = ReflectHelper . TypeFromAssembly ( clientNamespace + "." + _commandClassName , driverAssemblyName , true ) ;
57
+ _oracleCommandBindByName = oracleCommandType . GetProperty ( "BindByName" ) ;
58
+
59
+ var parameterType = ReflectHelper . TypeFromAssembly ( clientNamespace + ".OracleParameter" , driverAssemblyName , true ) ;
60
+ _oracleDbType = parameterType . GetProperty ( "OracleDbType" ) ;
61
+
62
+ var oracleDbTypeEnum = ReflectHelper . TypeFromAssembly ( clientNamespace + ".OracleDbType" , driverAssemblyName , true ) ;
63
+ _oracleDbTypeRefCursor = Enum . Parse ( oracleDbTypeEnum , "RefCursor" ) ;
64
+ _oracleDbTypeXmlType = Enum . Parse ( oracleDbTypeEnum , "XmlType" ) ;
65
+ }
66
+
67
+ /// <inheritdoc/>
68
+ public override bool UseNamedPrefixInSql => true ;
69
+
70
+ /// <inheritdoc/>
71
+ public override bool UseNamedPrefixInParameter => true ;
72
+
73
+ /// <inheritdoc/>
74
+ public override string NamedPrefix => ":" ;
75
+
76
+ /// <remarks>
77
+ /// Add logic to ensure that a <see cref="DbType.Boolean"/> parameter is not created since
78
+ /// ODP.NET doesn't support it. Handle <see cref="DbType.Guid"/> and <see cref="DbType.Xml"/> cases too.
79
+ /// Adjust <see cref="DbType.String"/> resulting type if needed.
80
+ /// </remarks>
81
+ protected override void InitializeParameter ( DbParameter dbParam , string name , SqlType sqlType )
82
+ {
83
+ switch ( sqlType . DbType )
84
+ {
85
+ case DbType . Boolean :
86
+ // if the parameter coming in contains a boolean then we need to convert it
87
+ // to another type since ODP.NET doesn't support DbType.Boolean
88
+ base . InitializeParameter ( dbParam , name , SqlTypeFactory . Int16 ) ;
89
+ break ;
90
+ case DbType . Guid :
91
+ base . InitializeParameter ( dbParam , name , _guidSqlType ) ;
92
+ break ;
93
+ case DbType . Xml :
94
+ InitializeParameter ( dbParam , name , _oracleDbTypeXmlType ) ;
95
+ break ;
96
+ default :
97
+ base . InitializeParameter ( dbParam , name , sqlType ) ;
98
+ break ;
99
+ }
100
+ }
101
+
102
+ private void InitializeParameter ( DbParameter dbParam , string name , object sqlType )
103
+ {
104
+ dbParam . ParameterName = FormatNameForParameter ( name ) ;
105
+ _oracleDbType . SetValue ( dbParam , sqlType , null ) ;
106
+ }
107
+
108
+ protected override void OnBeforePrepare ( DbCommand command )
109
+ {
110
+ base . OnBeforePrepare ( command ) ;
111
+
112
+ // need to explicitly turn on named parameter binding
113
+ // http://tgaw.wordpress.com/2006/03/03/ora-01722-with-odp-and-command-parameters/
114
+ _oracleCommandBindByName . SetValue ( command , true , null ) ;
115
+
116
+ var detail = CallableParser . Parse ( command . CommandText ) ;
117
+
118
+ if ( ! detail . IsCallable )
119
+ return ;
120
+
121
+ command . CommandType = CommandType . StoredProcedure ;
122
+ command . CommandText = detail . FunctionName ;
123
+ _oracleCommandBindByName . SetValue ( command , false , null ) ;
124
+
125
+ var outCursor = command . CreateParameter ( ) ;
126
+ _oracleDbType . SetValue ( outCursor , _oracleDbTypeRefCursor , null ) ;
127
+
128
+ outCursor . Direction = detail . HasReturn ? ParameterDirection . ReturnValue : ParameterDirection . Output ;
129
+
130
+ command . Parameters . Insert ( 0 , outCursor ) ;
131
+ }
132
+
133
+ System . Type IEmbeddedBatcherFactoryProvider . BatcherFactoryClass => typeof ( OracleDataClientBatchingBatcherFactory ) ;
134
+ }
135
+ }
0 commit comments