方針
- コンストラクタで接続(デストラクタで切断)
- プロバイダファクトリクラス(DbProviderFactory)を利用する。
- Oracle 固有クラスについてはリフレクションを使用する。
- Oracle 固有クラスを利用する場合は独立した関数を作成する。
- パラメータの「名前によるバインド」(BindByName)をデフォルトにする。
コード
ODP.NET管理対象外ドライバ前提です。ODP.NET管理対象ドライバを使用する場合は、Oracle.DataAccess.Client
の部分を Oracle.ManagedDataAccess
に書き換えてください。(未テスト)
ODP.NET管理対象ドライバについてはこちらに良いまとめがあります。
ODP.NET Managed Driver(管理対象ドライバ)についての私的まとめ - しばたテックブログ
ODP.NET Managed Driverについて自分の欲しい形でまとまった資料がなかったのでここでまとめておきます。 ODP.NET Managed Driver(管理対象ドライバ)とは ODP.NET Managed Driver(管理対象ドライバ)とはOracle 12cから追加された新しい形のODP.NETで…
VB.NET
Imports System
Imports System.Data
Imports System.Data.Common
Public Class DbFacade
Implements IDisposable
Private _factory As DbProviderFactory
Private _cnn As DbConnection
Private _cmd As DbCommand
Private _txn As DbTransaction
Public Sub New()
Me.New("Data Source=ExampleDb;User ID=SCOTT;Password=TIGER")
End Sub
Public Sub New(ByVal connectionString As String)
_factory = DbProviderFactories.GetFactory("Oracle.DataAccess.Client")
DbConnect(connectionString)
End Sub
Public Function DbConnect(ByVal connectionString As String) As DbConnection
_cnn = _factory.CreateConnection()
Me.ConnectionString = connectionString
Return _cnn
End Function
Public Property ConnectionString() As String
Get
Return _cnn.ConnectionString
End Get
Set(ByVal value As String)
If _cnn.ConnectionString <> value Then
_cnn.ConnectionString = value
End If
End Set
End Property
Public Sub Open()
If _cnn.State = ConnectionState.Closed Then _cnn.Open()
End Sub
Public Sub Close()
ClearParams()
If _cnn.State = ConnectionState.Open Then _cnn.Close()
End Sub
''' <summary>
''' BindByNameプロパティをセットする
''' </summary>
''' <param name="isName">True:有効 False:無効</param>
Private Sub SetBindByName(ByVal cmd As DbCommand, ByVal isName As Boolean)
cmd.GetType().GetProperty("BindByName").SetValue(cmd, isName, Nothing)
End Sub
Public Function CreateCommand() As DbCommand
Dim cmd As DbCommand = _factory.CreateCommand()
cmd.Connection = _cnn
SetBindByName(cmd, True)
Return cmd
End Function
Public Function CreateCommand(ByVal sql As String) As DbCommand
Dim cmd As DbCommand = CreateCommand()
cmd.CommandText = sql
Return cmd
End Function
Public Function CreateDataAdapter() As DbDataAdapter
Return _factory.CreateDataAdapter()
End Function
''' <summary>
''' パラメータを追加する。
''' </summary>
''' <param name="cmd"></param>
''' <param name="param"></param>
''' <remarks>Removeしなければ、「PLS-00703: リストに名前付き引数のインスタンスが複数あります。」が発生する</remarks>
Private Sub AddParam(ByVal cmd As DbCommand, ByVal param As DbParameter)
If cmd.Parameters.Contains(cmd.Parameters(param.ParameterName)) Then
cmd.Parameters.Remove(cmd.Parameters(param.ParameterName))
End If
cmd.Parameters.Add(param)
End Sub
''' <summary>
''' パラメータを追加する
''' </summary>
''' <param name="name">名称</param>
''' <param name="value">値</param>
''' <param name="type">DbType</param>
Public Function AddParam(ByVal name As String, ByVal value As Object, ByVal type As DbType) As IDataParameter
If value.GetType().IsArray Then
Return AddParamPLSQLAssociativeArray(name, value, type)
End If
If _cmd Is Nothing Then _cmd = CreateCommand()
Dim param As DbParameter = _cmd.CreateParameter
param.ParameterName = name
param.DbType = type
param.Value = value
AddParam(_cmd, param)
Return param
End Function
''' <summary>
''' パラメータを追加する
''' </summary>
''' <param name="name">名称</param>
''' <param name="type">DbType</param>
''' <param name="direction">Direction</param>
''' <param name="size">Size</param>
''' <remarks>ストアド戻り値用</remarks>
Public Function AddParam(ByVal name As String, ByVal type As DbType, ByVal direction As ParameterDirection, ByVal size As Integer) As IDataParameter
If _cmd Is Nothing Then _cmd = CreateCommand()
Dim param As DbParameter = _cmd.CreateParameter()
param.ParameterName = name
param.DbType = type
param.Direction = direction
param.Size = size
AddParam(_cmd, param)
Return param
End Function
''' <summary>
''' パラメータを追加する
''' </summary>
''' <param name="cmd">DbCommand</param>
''' <param name="name">名称</param>
''' <param name="sourceColumn">列名</param>
''' <param name="type">DbType</param>
''' <remarks>DataAdapter用</remarks>
Public Function AddParam(ByVal cmd As DbCommand, ByVal name As String, ByVal sourceColumn As String, ByVal type As DbType) As IDataParameter
Dim param As DbParameter = cmd.CreateParameter()
param.ParameterName = name
param.SourceColumn = sourceColumn
param.DbType = type
AddParam(cmd, param)
Return param
End Function
''' <summary>
''' RefCursor型のパラメータを追加する
''' </summary>
''' <param name="name">名称</param>
Public Function AddParamRefCursor(ByVal name As String) As IDataParameter
If _cmd Is Nothing Then _cmd = CreateCommand()
Dim asm As System.Reflection.Assembly = _factory.GetType().Assembly
Dim paramType As Type = asm.GetType("Oracle.DataAccess.Client.OracleParameter")
Dim param As Object = Activator.CreateInstance(paramType)
paramType.GetProperty("ParameterName").SetValue(param, name, Nothing)
paramType.GetProperty("Direction").SetValue(param, ParameterDirection.Output, Nothing)
Dim oraDbType As Type = asm.GetType("Oracle.DataAccess.Client.OracleDbType")
paramType.GetProperty("OracleDbType").SetValue(param, oraDbType.GetField("RefCursor").GetValue(Nothing), Nothing)
AddParam(_cmd, DirectCast(param, DbParameter))
Return DirectCast(param, IDataParameter)
End Function
''' <summary>
''' PL/SQL連想配列のパラメータを追加する
''' </summary>
''' <param name="name">名称</param>
''' <param name="value">値</param>
''' <param name="type">DbType</param>
Public Function AddParamPLSQLAssociativeArray(ByVal name As String, ByVal value As Object, ByVal type As DbType) As IDataParameter
If _cmd Is Nothing Then _cmd = CreateCommand()
Dim asm As System.Reflection.Assembly = _factory.GetType().Assembly
Dim oraParamType As Type = asm.GetType("Oracle.DataAccess.Client.OracleParameter")
Dim oraParam As Object = Activator.CreateInstance(oraParamType)
oraParamType.GetProperty("ParameterName").SetValue(oraParam, name, Nothing)
oraParamType.GetProperty("Size").SetValue(oraParam, CType(value, Array).Length, Nothing)
Dim oraCollectionType As Type = asm.GetType("Oracle.DataAccess.Client.OracleCollectionType")
oraParamType.GetProperty("CollectionType").SetValue(oraParam, oraCollectionType.GetField("PLSQLAssociativeArray").GetValue(Nothing), Nothing)
Dim param As IDataParameter = DirectCast(oraParam, IDataParameter)
param.DbType = type
param.Value = value
AddParam(_cmd, DirectCast(param, DbParameter))
Return param
End Function
''' <summary>
''' パラメータをクリアする
''' </summary>
Public Sub ClearParams()
If _cmd Is Nothing Then Exit Sub
_cmd.Parameters.Clear()
End Sub
''' <summary>
''' DataTableを返す
''' </summary>
''' <param name="sql"></param>
Public Function GetDataTable(ByVal sql As String) As DataTable
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = sql
Dim da As DbDataAdapter = _factory.CreateDataAdapter()
da.SelectCommand = _cmd
Dim dt As DataTable = New DataTable
da.Fill(dt)
Return dt
End Function
''' <summary>
''' RefCursorをDataSetにセットする
''' </summary>
''' <param name="dataSet"></param>
''' <param name="procedureName"></param>
Public Sub FillRefCursor(ByRef dataSet As DataSet, ByVal procedureName As String)
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = procedureName
_cmd.CommandType = CommandType.StoredProcedure
Dim da As DbDataAdapter = _factory.CreateDataAdapter()
da.SelectCommand = _cmd
da.Fill(dataSet)
End Sub
''' <summary>
''' RefCursorをDataTableにセットする
''' </summary>
''' <param name="dataTable"></param>
''' <param name="procedureName"></param>
Public Sub FillRefCursor(ByRef dataTable As DataTable, ByVal procedureName As String)
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = procedureName
_cmd.CommandType = CommandType.StoredProcedure
Dim da As DbDataAdapter = _factory.CreateDataAdapter()
da.SelectCommand = _cmd
da.Fill(dataTable)
End Sub
''' <summary>
''' SQLを実行する
''' </summary>
''' <param name="sql"></param>
Public Function ExecuteSql(ByVal sql As String) As Integer
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = sql
Open()
Dim result As Integer = _cmd.ExecuteNonQuery()
If _txn Is Nothing OrElse _txn.Connection Is Nothing Then
Close()
End If
Return result
End Function
''' <summary>
''' ストアドプロシージャを実行する
''' </summary>
''' <param name="procedureName"></param>
Public Function ExecuteStored(ByVal procedureName As String) As Integer
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandType = CommandType.StoredProcedure
_cmd.CommandText = procedureName
Open()
Dim result As Integer = _cmd.ExecuteNonQuery()
If _txn Is Nothing OrElse _txn.Connection Is Nothing Then
Close()
End If
Return result
End Function
Public Function ExecuteReader(ByVal sql As String) As DbDataReader
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = sql
Open()
Dim result As DbDataReader = _cmd.ExecuteReader(CommandBehavior.CloseConnection)
' Close()
Return result
End Function
Public Function ExecuteScalar(ByVal sql As String) As Object
If _cmd Is Nothing Then _cmd = CreateCommand()
_cmd.CommandText = sql
Open()
Dim result as Object =_cmd.ExecuteScalar()
Close()
Return result
End Function
Public Sub BeginTransaction()
Open()
_txn = _cnn.BeginTransaction()
End Sub
Public Sub Commit()
_txn.Commit()
Close()
End Sub
Public Sub Rollback()
_txn.Rollback()
Close()
End Sub
Private disposedValue As Boolean = False ' 重複する呼び出しを検出するには
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: 明示的に呼び出されたときにマネージ リソースを解放します
If _txn IsNot Nothing Then _txn.Dispose()
If _cmd IsNot Nothing Then _cmd.Dispose()
If _cnn IsNot Nothing Then
If _cnn.State = ConnectionState.Open Then
_cnn.Close()
End If
_cnn.Dispose()
End If
End If
' TODO: 共有のアンマネージ リソースを解放します
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
Public Sub Dispose() Implements IDisposable.Dispose
' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
C#
using System;
using System.Data;
using System.Data.Common;
public class DbFacade : IDisposable
{
private DbProviderFactory _factory;
private DbConnection _cnn;
private DbCommand _cmd;
private DbTransaction _txn;
public DbFacade() : this("Data Source=ExampleDb;User ID=SCOTT;Password=TIGER"){}
public DbFacade(string connectionString)
{
_factory = DbProviderFactories.GetFactory("Oracle.DataAccess.Client");
DbConnect(connectionString);
}
public DbConnection DbConnect(string connectionString)
{
_cnn = _factory.CreateConnection();
ConnectionString = connectionString;
return _cnn;
}
public string ConnectionString
{
get
{
return _cnn.ConnectionString;
}
set
{
if ((_cnn.ConnectionString != value))
{
_cnn.ConnectionString = value;
}
}
}
public void Open()
{
if ((_cnn.State == ConnectionState.Closed))
{
_cnn.Open();
}
}
void Close()
{
ClearParams();
if (_cnn.State == ConnectionState.Open)
{
_cnn.Close();
}
}
/// <summary>
/// BindByNameプロパティをセットする
/// </summary>
/// <param name="isName">True:有効 False:無効</param>
void SetBindByName(DbCommand cmd, bool isName)
{
cmd.GetType().GetProperty("BindByName").SetValue(cmd, isName, null);
}
public DbCommand CreateCommand()
{
DbCommand cmd = _factory.CreateCommand();
cmd.Connection = _cnn;
SetBindByName(cmd, true);
return cmd;
}
public DbCommand CreateCommand(string sql)
{
DbCommand cmd = CreateCommand();
cmd.CommandText = sql;
return cmd;
}
public DbDataAdapter CreateDataAdapter()
{
return _factory.CreateDataAdapter();
}
/// <summary>
/// パラメータを追加する。
/// </summary>
/// <param name="cmd"></param>
/// <param name="param"></param>
/// <remarks>Removeしなければ、「PLS-00703: リストに名前付き引数のインスタンスが複数あります。」が発生する</remarks>
private void AddParam(DbCommand cmd, DbParameter param)
{
if (cmd.Parameters.Contains(cmd.Parameters[param.ParameterName]))
{
cmd.Parameters.Remove(cmd.Parameters[param.ParameterName]);
}
cmd.Parameters.Add(param);
}
/// <summary>
/// パラメータを追加する
/// </summary>
/// <param name="name">名称</param>
/// <param name="value">値</param>
/// <param name="type">DbType</param>
public IDataParameter AddParam(string name, object value, DbType type)
{
if (value.GetType().IsArray)
{
return AddParamPLSQLAssociativeArray(name, value, type);
}
if (_cmd == null)
{
_cmd = CreateCommand();
}
DbParameter param = _cmd.CreateParameter();
param.ParameterName = name;
param.DbType = type;
param.Value = value;
AddParam(_cmd, param);
return param;
}
/// <summary>
/// パラメータを追加する
/// </summary>
/// <param name="name">名称</param>
/// <param name="type">DbType</param>
/// <param name="direction">Direction</param>
/// <param name="size">Size</param>
/// <remarks>ストアド戻り値用</remarks>
public IDataParameter AddParam(string name, DbType type, ParameterDirection direction, int size)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
DbParameter param = _cmd.CreateParameter();
param.ParameterName = name;
param.DbType = type;
param.Direction = direction;
param.Size = size;
AddParam(_cmd, param);
return param;
}
/// <summary>
/// パラメータを追加する
/// </summary>
/// <param name="cmd">DbCommand</param>
/// <param name="name">名称</param>
/// <param name="sourceColumn">列名</param>
/// <param name="type">DbType</param>
/// <remarks>DataAdapter用</remarks>
public IDataParameter AddParam(DbCommand cmd, string name, string sourceColumn, DbType type)
{
DbParameter param = cmd.CreateParameter();
param.ParameterName = name;
param.SourceColumn = sourceColumn;
param.DbType = type;
AddParam(cmd, param);
return param;
}
/// <summary>
/// RefCursor型のパラメータを追加する
/// </summary>
/// <param name="name">名称</param>
public IDataParameter AddParamRefCursor(string name)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
System.Reflection.Assembly asm = _factory.GetType().Assembly;
Type paramType = asm.GetType("Oracle.DataAccess.Client.OracleParameter");
object param = Activator.CreateInstance(paramType);
paramType.GetProperty("ParameterName").SetValue(param, name, null);
paramType.GetProperty("Direction").SetValue(param, ParameterDirection.Output, null);
Type oraDbType = asm.GetType("Oracle.DataAccess.Client.OracleDbType");
paramType.GetProperty("OracleDbType").SetValue(param, oraDbType.GetField("RefCursor").GetValue(null), null);
AddParam(_cmd, param as DbParameter);
return param as IDataParameter;
}
/// <summary>
/// PL/SQL連想配列のパラメータを追加する
/// </summary>
/// <param name="name">名称</param>
/// <param name="value">値</param>
/// <param name="type">DbType</param>
public IDataParameter AddParamPLSQLAssociativeArray(string name, object value, DbType type)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
System.Reflection.Assembly asm = _factory.GetType().Assembly;
Type oraParamType = asm.GetType("Oracle.DataAccess.Client.OracleParameter");
object oraParam = Activator.CreateInstance(oraParamType);
oraParamType.GetProperty("ParameterName").SetValue(oraParam, name, null);
oraParamType.GetProperty("Size").SetValue(oraParam, ((Array)(value)).Length, null);
Type oraCollectionType = asm.GetType("Oracle.DataAccess.Client.OracleCollectionType");
oraParamType.GetProperty("CollectionType").SetValue(oraParam, oraCollectionType.GetField("PLSQLAssociativeArray").GetValue(null), null);
IDataParameter param = ((IDataParameter)(oraParam));
param.DbType = type;
param.Value = value;
AddParam(_cmd, param as DbParameter);
return param;
}
/// <summary>
/// パラメータをクリアする
/// </summary>
public void ClearParams()
{
if (_cmd == null)
{
return;
}
_cmd.Parameters.Clear();
}
/// <summary>
/// DataTableを返す
/// </summary>
/// <param name="sql"></param>
public DataTable GetDataTable(string sql)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = sql;
DbDataAdapter da = _factory.CreateDataAdapter();
da.SelectCommand = _cmd;
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
/// <summary>
/// RefCursorをDataSetにセットする
/// </summary>
/// <param name="dataSet"></param>
/// <param name="procedureName"></param>
public void FillRefCursor(ref DataSet dataSet, string procedureName)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = procedureName;
_cmd.CommandType = CommandType.StoredProcedure;
DbDataAdapter da = _factory.CreateDataAdapter();
da.SelectCommand = _cmd;
da.Fill(dataSet);
}
/// <summary>
/// RefCursorをDataTableにセットする
/// </summary>
/// <param name="dataTable"></param>
/// <param name="procedureName"></param>
public void FillRefCursor(ref DataTable dataTable, string procedureName)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = procedureName;
_cmd.CommandType = CommandType.StoredProcedure;
DbDataAdapter da = _factory.CreateDataAdapter();
da.SelectCommand = _cmd;
da.Fill(dataTable);
}
/// <summary>
/// SQLを実行する
/// </summary>
/// <param name="sql"></param>
public int ExecuteSql(string sql)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = sql;
Open();
int result = _cmd.ExecuteNonQuery();
if (_txn == null || _txn.Connection == null)
{
Close();
};
return result;
}
/// <summary>
/// ストアドプロシージャを実行する
/// </summary>
/// <param name="procedureName"></param>
public int ExecuteStored(string procedureName)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.CommandText = procedureName;
Open();
int result = _cmd.ExecuteNonQuery();
if (_txn == null || _txn.Connection == null)
{
Close();
};
return result;
}
public DbDataReader ExecuteReader(string sql)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = sql;
Open();
DbDataReader result = _cmd.ExecuteReader(CommandBehavior.CloseConnection);
// Close();
return result;
}
public object ExecuteScalar(string sql)
{
if (_cmd == null)
{
_cmd = CreateCommand();
}
_cmd.CommandText = sql;
Open();
object result = _cmd.ExecuteScalar();
Close();
return result;
}
public void BeginTransaction()
{
Open();
_txn = _cnn.BeginTransaction();
}
public void Commit()
{
_txn.Commit();
Close();
}
public void Rollback()
{
_txn.Rollback();
Close();
}
#region IDisposable Support
private bool disposedValue = false; // 重複する呼び出しを検出するには
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
if (_txn != null)
{
_txn.Dispose();
}
if (_cmd != null)
{
_cmd.Dispose();
}
if (_cnn != null)
{
if (_cnn.State == ConnectionState.Open)
{
_cnn.Close();
}
_cmd.Dispose();
}
}
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
// TODO: 大きなフィールドを null に設定します。
disposedValue = true;
}
}
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
// ~DbFacade() {
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
// Dispose(false);
// }
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
public void Dispose()
{
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
Dispose(true);
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
// GC.SuppressFinalize(this);
}
#endregion
}
利用方法
とりあえず、
VB.NET
Using db As New DbFacade()
'Update
db.ExecuteSql("UPDATE emp SET sal=sal*1.1 WHERE empno=7369")
'DataTable
Dim dt As DataTable = db.GetDataTable("select * from EMP")
End Using
C#
using (DbFacade db = new DbFacade())
{
// Update
db.ExecuteSql("UPDATE emp SET sal=sal*1.1 WHERE empno=7369");
// DataTable
DataTable dt = db.GetDataTable("select * from EMP");
}
No comments:
Post a Comment