Skip to content

Commit fb5d5a4

Browse files
NH-4062 - Refactoring ODP.Net drivers for eliminating code duplication.
1 parent d938eef commit fb5d5a4

File tree

4 files changed

+142
-236
lines changed

4 files changed

+142
-236
lines changed
Lines changed: 3 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,19 @@
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-
101
namespace NHibernate.Driver
112
{
123
/// <summary>
13-
/// A NHibernate Driver for using the Oracle.DataAccess DataProvider
4+
/// A NHibernate Driver for using the Oracle.DataAccess (unmanaged) DataProvider
145
/// </summary>
15-
/// <remarks>
16-
/// 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 class OracleDataClientDriver : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider
6+
public class OracleDataClientDriver : OracleDataClientDriverBase
217
{
22-
private const string driverAssemblyName = "Oracle.DataAccess";
23-
private const string connectionTypeName = "Oracle.DataAccess.Client.OracleConnection";
24-
private const string commandTypeName = "Oracle.DataAccess.Client.OracleCommand";
25-
private static readonly SqlType GuidSqlType = new SqlType(DbType.Binary, 16);
26-
private readonly PropertyInfo oracleCommandBindByName;
27-
private readonly PropertyInfo oracleDbType;
28-
private readonly object oracleDbTypeRefCursor;
29-
private readonly object oracleDbTypeXmlType;
30-
318
/// <summary>
329
/// Initializes a new instance of <see cref="OracleDataClientDriver"/>.
3310
/// </summary>
3411
/// <exception cref="HibernateException">
3512
/// Thrown when the <c>Oracle.DataAccess</c> assembly can not be loaded.
3613
/// </exception>
3714
public OracleDataClientDriver()
38-
: base(
39-
"Oracle.DataAccess.Client",
40-
driverAssemblyName,
41-
connectionTypeName,
42-
commandTypeName)
15+
: base(false)
4316
{
44-
System.Type oracleCommandType = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleCommand", driverAssemblyName, false);
45-
oracleCommandBindByName = oracleCommandType.GetProperty("BindByName");
46-
47-
System.Type parameterType = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleParameter", driverAssemblyName, false);
48-
oracleDbType = parameterType.GetProperty("OracleDbType");
49-
50-
System.Type oracleDbTypeEnum = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleDbType", driverAssemblyName, false);
51-
oracleDbTypeRefCursor = Enum.Parse(oracleDbTypeEnum, "RefCursor");
52-
oracleDbTypeXmlType = Enum.Parse(oracleDbTypeEnum, "XmlType");
53-
}
54-
55-
/// <summary></summary>
56-
public override bool UseNamedPrefixInSql
57-
{
58-
get { return true; }
59-
}
60-
61-
/// <summary></summary>
62-
public override bool UseNamedPrefixInParameter
63-
{
64-
get { return true; }
65-
}
66-
67-
/// <summary></summary>
68-
public override string NamedPrefix
69-
{
70-
get { return ":"; }
71-
}
72-
73-
/// <remarks>
74-
/// This adds logic to ensure that a DbType.Boolean parameter is not created since
75-
/// ODP.NET doesn't support it.
76-
/// </remarks>
77-
protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType)
78-
{
79-
// if the parameter coming in contains a boolean then we need to convert it
80-
// to another type since ODP.NET doesn't support DbType.Boolean
81-
switch (sqlType.DbType)
82-
{
83-
case DbType.Boolean:
84-
base.InitializeParameter(dbParam, name, SqlTypeFactory.Int16);
85-
break;
86-
case DbType.Guid:
87-
base.InitializeParameter(dbParam, name, GuidSqlType);
88-
break;
89-
case DbType.Xml:
90-
this.InitializeParameter(dbParam, name, oracleDbTypeXmlType);
91-
break;
92-
default:
93-
base.InitializeParameter(dbParam, name, sqlType);
94-
break;
95-
}
96-
}
97-
98-
private void InitializeParameter(DbParameter dbParam, string name, object sqlType)
99-
{
100-
dbParam.ParameterName = FormatNameForParameter(name);
101-
oracleDbType.SetValue(dbParam, sqlType, null);
102-
}
103-
104-
protected override void OnBeforePrepare(DbCommand command)
105-
{
106-
base.OnBeforePrepare(command);
107-
108-
// need to explicitly turn on named parameter binding
109-
// http://tgaw.wordpress.com/2006/03/03/ora-01722-with-odp-and-command-parameters/
110-
oracleCommandBindByName.SetValue(command, true, null);
111-
112-
CallableParser.Detail detail = CallableParser.Parse(command.CommandText);
113-
114-
if (!detail.IsCallable)
115-
return;
116-
117-
command.CommandType = CommandType.StoredProcedure;
118-
command.CommandText = detail.FunctionName;
119-
oracleCommandBindByName.SetValue(command, false, null);
120-
121-
var outCursor = command.CreateParameter();
122-
oracleDbType.SetValue(outCursor, oracleDbTypeRefCursor, null);
123-
124-
outCursor.Direction = detail.HasReturn ? ParameterDirection.ReturnValue : ParameterDirection.Output;
125-
126-
command.Parameters.Insert(0, outCursor);
127-
}
128-
129-
System.Type IEmbeddedBatcherFactoryProvider.BatcherFactoryClass
130-
{
131-
get { return typeof (OracleDataClientBatchingBatcherFactory); }
13217
}
13318
}
13419
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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

Comments
 (0)