プライマリ・コンテンツに移動

Oracle® Data Provider for .NET開発者ガイド ODAC 12.2c リリース1 (12.2.0.1) for Microsoft Windows E88311-03 |
| 目次 | 索引

前 | 次 |

# OracleCommandオブジェクト

`OracleCommand`オブジェクトは、Oracle Databaseで実行されるSQL文またはストアド・プロシージャを表します。

注意:

オプティマイザのヒント構文形式`--+ ...`はサポートされていません。ODP.NETでは、`/*+ ... */`の構文をサポートしています。

この項の内容は次のとおりです。

- トランザクション

- System.TransactionsとPromotable Transaction

- パラメータ・バインド

- バッチ処理

- 文キャッシング

- 自動チューニング

## トランザクション

Oracle Databaseは、接続のコンテキストでのみトランザクションを開始します。トランザクションが開始すると、その接続で引き続き行われるコマンド実行はすべて、そのトランザクションのコンテキストで実行されます。トランザクションは`OracleConnection`オブジェクトでのみ開始され、`OracleCommand`オブジェクトの`Transaction`読取り専用プロパティは、`OracleConnection`オブジェクトによって暗黙的に設定されます。このため、アプリケーションは`Transaction`プロパティを設定できません。また、設定する必要もありません。

注意:

トランザクションは、.NETストアド・プロシージャではサポートされません。

`"FOR` `UPDATE"`および`"RETURNING"`句を含むSQL文には明示的なトランザクションが必要です。グローバル・トランザクションが使用されていない場合は不要です。

## System.TransactionsとPromotable Transaction

ODP.NETは`System.Transactions`をサポートします。Oracle Database 11gリリース(11.1)以上の`System.Transactions`スコープでオープンされた最初の接続に対しては、ローカル・トランザクションが作成されます。2番目の接続がオープンされると、このトランザクションは自動的に分散トランザクションに昇格します。この機能は、パフォーマンスとスケーラビリティの向上を実現します。

`TransactionScope`や`ServicedComponent`などのトランザクション・コンテキスト内で作成された接続は、様々なリリースのOracle Databaseに対して確立できます。ただし、ローカル・トランザクションを昇格できるようにするには、次の条件を満たす必要があります。

- Oracle Database 11gリリース1(11.1)以上のインスタンスに対してトランザクション・コンテキストの最初の接続を確立する必要があります。

- トランザクション・コンテキスト内でオープンになっているすべての接続の`"Promotable Transaction"`設定が`"promotable"`に設定されている必要があります。`"Promotable Transaction"`設定が`"local"`に設定されている場合、同じトランザクション・コンテキスト内にある後続の接続をオープンしようとすると、例外がスローされます。

- ローカル・トランザクションの昇格には11.1.0.7.20以上のOracle Services for Microsoft Transaction Serverが必要です。この要件を満たしていない場合、同じトランザクション・コンテキスト内にある2番目の接続要求で例外がスローされます。

データベースのトランザクションがすでに分散されているときにトランザクションを昇格すると、データベース・リンクの使用によりORA-24797エラーがスローされます。

レジストリ、構成ファイル(マシン、Web、アプリケーション)または`"PromotableTransaction"`接続文字列属性で、`"Promotable Transaction"`の値として`"local"`を設定すると、ローカル・トランザクションに関連付けられているトランザクション・コンテキスト内でオープンできる接続は1つのみになります。このようなローカル・トランザクションは昇格できません。ODP.NET 12.1.0.2以降、`Promotable Transaction`設定を`local`に設定した接続はローカル・トランザクションとして開始され、ローカル・トランザクションのままになります。トランザクションに加わるために2回目の接続を試みると、例外がスローされます。

アプリケーションが`System.Transactions`を使用する場合は、`enlist`接続文字列属性を`true`(デフォルト)または`dynamic`のいずれかに設定する必要があります。ただし、自動登録するには`enlist=true`である必要があるため、`TransactionScope`とともに`enlist=dynamic`を使用することはできません。

ODP.NETは、分散トランザクションを使用するアプリケーション用に、次の`System.Transactions`プログラミング・モデルをサポートしています。

- TransactionScopeを使用した暗黙的なトランザクション登録

- CommittableTransactionを使用した明示的なトランザクション登録。

- 旧リリースのデータベースにおけるローカル・トランザクション・サポート

関連項目:

Oracle Database 11gリリース1(11.1)より前のインスタンスに接続するアプリケーションについては、旧リリースのデータベースにおけるローカル・トランザクション・サポートを参照してください。この項では、Promotable Transactionの設定を使用してODP.NETの動作を制御する方法について説明します。

### TransactionScopeを使用した暗黙的なトランザクション登録

`TransactionScope`クラスは、トランザクションに明示的に登録する必要のないトランザクション・アプリケーションを記述するためのメカニズムを提供します。これを実現するには、アプリケーションで`TransactionScope`オブジェクトを使用して、トランザクション・コードを定義します。このトランザクション・スコープ内で作成された接続は、分散トランザクションへの昇格が可能なローカル・トランザクションに登録されます。

注意:

デフォルトでは、最初の接続がOracle Database 11gリリース1(11.1)より前のインスタンスに対してオープンされた場合、その接続は分散トランザクションとして登録されます。

旧リリースのデータベースにおけるローカル・トランザクション・サポート」で説明する手順を使用して、トランザクションをローカル・トランザクションとして作成することも可能です。ただし、その場合のトランザクションは分散トランザクションに昇格できません。

変更をコミットするには、アプリケーションで`TransactionScope`オブジェクトに対して`Complete`メソッドをコールする必要があります。コールしない場合、トランザクションはデフォルトで強制終了します。

    // C#

    using System;
    using Oracle.DataAccess.Client;
    using System.Data;
    using System.Data.Common;
    using System.Transactions;

    class psfTxnScope
    {
      static void Main()
      {
        int retVal = 0;
        string providerName = "Oracle.DataAccess.Client";
        string constr =
               @"User Id=scott;Password=tiger;Data Source=oracle;enlist=true";

        // Get the provider factory.
        DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);

        try
        {
          // Create a TransactionScope object, (It will start an ambient
          // transaction automatically).
          using (TransactionScope scope = new TransactionScope())
          {
            // Create first connection object.
            using (DbConnection conn1 = factory.CreateConnection())
            {
              // Set connection string and open the connection. this connection
              // will be automatically enlisted in a promotable local transaction.
              conn1.ConnectionString = constr;
              conn1.Open();

              // Create a command to execute the sql statement.
              DbCommand  cmd1 = factory.CreateCommand();
              cmd1.Connection = conn1;
              cmd1.CommandText = @"insert into emp (empno, ename, job) values
                                                         (1234, 'emp1', 'dev1')";

              // Execute the SQL statement to insert one row in DB.
              retVal = cmd1.ExecuteNonQuery();
              Console.WriteLine("Rows to be affected by cmd1: {0}", retVal);

              // Close the connection and dispose the command object.
              conn1.Close();
              conn1.Dispose();
              cmd1.Dispose();
            }

            // The Complete method commits the transaction. If an exception has
            // been thrown or Complete is not called then the transaction is
            // rolled back.
            scope.Complete();
          }
        }
        catch (Exception ex)
        {
          Console.WriteLine(ex.Message);
          Console.WriteLine(ex.StackTrace);
        }
      }
    }

### CommittableTransactionを使用した明示的なトランザクション登録

`CommittableTransaction`オブジェクトと`EnlistTransaction`メソッドのインスタンス化により、接続を明示的に作成してトランザクションに登録できます。アプリケーションでは、`CommittableTransaction`オブジェクトに対して`Commit`または`Rollback`をコールする必要があります。

    // C#

    using System;
    using Oracle.DataAccess.Client;
    using System.Data;
    using System.Data.Common;
    using System.Transactions;

    class psfEnlistTransaction
    {
      static void Main()
      {
        int retVal = 0;
        string providerName = "Oracle.DataAccess.Client";
        string constr =
               @"User Id=scott;Password=tiger;Data Source=oracle;enlist=dynamic";

        // Get the provider factory.
        DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);

        try
        {
          // Create a committable transaction object.
          CommittableTransaction cmtTx = new CommittableTransaction();

          // Open a connection to the DB.
          DbConnection conn1 = factory.CreateConnection();
          conn1.ConnectionString = constr;
          conn1.Open();

          // enlist the connection with the commitable transaction.
          conn1.EnlistTransaction(cmtTx);

          // Create a command to execute the sql statement.
          DbCommand cmd1 = factory.CreateCommand();
          cmd1.Connection = conn1;
          cmd1.CommandText = @"insert into emp (empno, ename, job) values
                                                         (1234, 'emp1', 'dev1')";

          // Execute the SQL statement to insert one row in DB.
          retVal = cmd1.ExecuteNonQuery();
          Console.WriteLine("Rows to be affected by cmd1: {0}", retVal);

          // commit/rollback the transaction.
          cmtTx.Commit();   // commits the txn.
          //cmtTx.Rollback(); // rolls back the txn.

          // close and dispose the connection
          conn1.Close();
          conn1.Dispose();
          cmd1.Dispose();
        }
        catch (Exception ex)
        {
          Console.WriteLine(ex.Message);
          Console.WriteLine(ex.StackTrace);
        }
      }
    }

関連項目:

EnlistTransaction

### 旧リリースのデータベースにおけるローカル・トランザクション・サポート

`TransactionScope`内の最初の接続がOracle Database 11gリリース1(11.1)より前のインスタンスに対してオープンされた場合、デフォルトでは分散トランザクションが作成されます。この項で説明する手順を使用すれば、最初の接続でローカル・トランザクションを作成することもできます。

`System.Transactions`スコープ内にローカル・トランザクションを作成するには、レジストリ、マシン/Web/アプリケーション構成ファイルまたは`"Promotable Transaction"`接続文字列属性の`PromotableTransaction`設定を`"local"`に設定します。

`"local"`が指定されている場合、`TransactionScope`でオープンした最初の接続ではローカル・トランザクションが使用されます。後続の接続が同じ`TransactionScope`でオープンされると例外がスローされます。`TransactionScope`ですでに接続がオープンしていて、`"Promotable Transaction=local"`の`OracleConnection`が同じ`TransactionScope`内でオープンされようとしている場合は例外がスローされます。

`"promotable"`が指定されている場合、同じ`TransactionScope`でオープンされる最初と後続の接続は、同じ分散トランザクション内で登録されます。

レジストリと接続文字列属性の両方が使用されていて異なる値に設定されている場合、接続文字列属性はレジストリ・エントリの値をオーバーライドします。どちらも設定されていない場合は`"promotable"`が使用されます。これはデフォルトの値で、分散トランザクションのみがサポートされているODP.NETの以前のバージョンと同じです。

ODP.NETの特定のバージョンに対するレジストリ・エントリは、ODP.NETのバージョンを使用するすべてのアプリケーションに適用します。

## パラメータ・バインド

`OracleParameter`オブジェクトの`DbType`プロパティが設定されている場合、`OracleParameter`オブジェクトの`OracleDbType`プロパティも変更されます。その逆も同じです。パラメータ・セットは最後に有効になります。アプリケーションはデータをバインドして、パラメータ値の.NETタイプから、ODP.NETで`DbType`と`OracleDbType`の両方のプロパティを推測します。ODP.NETを使用すると、アプリケーションでは、出力パラメータを.NET FrameworkタイプまたはODP.NETタイプのいずれかとして取得できます。アプリケーションでは、出力パラメータの`DbType`プロパティ(.NETタイプ)、または`OracleParameter`オブジェクトの`OracleDbType`プロパティ(ODP.NETタイプ)を設定することで、出力パラメータに対してどちらのタイプを戻すかを指定できます。たとえば、`DbType`プロパティを設定することで出力パラメータが`DbType.String`型として設定されている場合、出力データは.NET String型として戻されます。一方、`OracleDbType`プロパティを設定することでパラメータが`OracleDbType.Char`として設定されている場合、出力データは`OracleString`型として戻されます。`DbType`と`OracleDbType`の両方のプロパティを設定してからコマンドを実行した場合は、最後の設定が有効になります。

ODP.NETは、次の`OracleCommand`メソッドの実行により、Oracleデータを`InputOutput`、`Output`および`ReturnValue`パラメータに移入します。

- `ExecuteReader`

- `ExecuteNonQuery`

- `ExecuteScalar`

アプリケーションは、出力パラメータの値をバインドできません。出力パラメータ値のバインドはODP.NETによって行われます。値オブジェクトが作成され、オブジェクトが`OracleParameter` `Value`プロパティに移入されます。

ファンクションに対して位置別(デフォルト)でバインドする場合、最初に他のパラメータより前にバインドされる戻り値がODP.NETに必要です。

この項の内容は次のとおりです。

- OracleDbTypeの列挙型

- DbType、OracleDbTypeおよび.NETタイプの判断

- PL/SQL連想配列バインド

- 配列バインド

関連項目:

OracleDbTypeの列挙

### コマンド・タイムアウト

コマンドをどのくらい実行すると例外で終了するか、その時間の長さは`OracleCommand` `CommandTimeout`プロパティによって制限されます。これを設定すると、長時間のコマンド実行でリソースが過剰に消費されたり、必要な他の操作が妨げられたりすることを避けられます。

データベース・サーバーは、アウト・オブ・バンド(OOB)で呼び出された場合はTCP/IP緊急データを介して、またイン・バンド・データで呼び出された場合はTCP/IP通常データを介して、それぞれ中断されることがあります。Windowsベースのデータベース・サーバーはイン・バンド中断しかサポートせず、他の(主としてUNIXベース)のデータベース・サーバーはOOBとイン・バンドどちらの中断もサポートします。

ODP.NET管理対象ドライバはデフォルトでOOB中断を使用し、データベース・サーバーがそれをサポートします。一部のネットワーク・トポロジの場合、データベースまでのルートに関係するルーターまたはファイアウォールが、緊急データまたはイン・バンド・データを削除するように構成されていた可能性があります。緊急データを適切に処理するようにルーターまたはファイアウォールを変更できない場合は、.NET構成パラメータ`Disable_Oob`を`on`に設定すれば、イン・バンド中断を使用するようにODP.NET管理対象ドライバを構成できます。

関連項目:

詳細は、「Oracle Data Provider for .NET管理対象ドライバ」の項で、「settingsセクション」を参照してください。

### OracleDbTypeの列挙型

`OracleDbType`の列挙値は、`OracleParameter`オブジェクトの`OracleDbType`を明示的に指定する際に使用されます。

表3-7では、すべての`OracleDbType`の列挙値と、それぞれの列挙値の説明をリストしています。

表3-7 OracleDbTypeの列挙値

メンバー名 | 説明
--- | ---
`Array` | Oracleコレクション(`VArray`またはネストされた表) ODP.NET管理対象ドライバでは使用できません
`BFile` | Oracle `BFILE`型
`BinaryFloat` | Oracle `BINARY_FLOAT`型
`BinaryDouble` | Oracle `BINARY_DOUBLE`型
`Blob` | Oracle `BLOB`型
`Boolean` | Oracle `BOOLEAN`型
`Byte` | `byte`型
`Char` | Oracle `CHAR`型
`Clob` | Oracle `CLOB`型
`Date` | Oracle `DATE`型
`Decimal` | Oracle `NUMBER`型
`Double` | 8バイトの`FLOAT`型
`Int16` | 2バイトの`INTEGER`型
`Int32` | 4バイトの`INTEGER`型
`Int64` | 8バイトの`INTEGER`型
`IntervalDS` | Oracle `INTERVAL` `DAY` `TO` `SECOND`型
`IntervalYM` | Oracle `INTERVAL` `YEAR` `TO` `MONTH`型
`Long` | Oracle `LONG`型
`LongRaw` | Oracle `LONG` `RAW`型
`NChar` | Oracle `NCHAR`型
`Object` | Oracle Object型 ODP.NET管理対象ドライバでは使用できません
`NClob` | Oracle `NCLOB`型
`NVarchar2` | Oracle `NVARCHAR2`型
`Raw` | Oracle `RAW`型
`Ref` | Oracle `REF`型 ODP.NET管理対象ドライバでは使用できません
`RefCursor` | Oracle `REF` `CURSOR`型
`Single` | 4バイトの`FLOAT`型
`TimeStamp` | Oracle `TIMESTAMP`型
`TimeStampLTZ` | Oracle `TIMESTAMP` `WITH` `LOCAL` `TIME` `ZONE`型
`TimeStampTZ` | Oracle `TIMESTAMP` `WITH` `TIME` `ZONE`型
`Varchar2` | Oracle `VARCHAR2`型
`XmlType` | Oracle `XMLType`型

注意:

PL/SQLの`LONG、LONG RAW、RAW`および`VARCHAR`データ型は、32512バイトまでのサイズにバインドできます。

### DbType、OracleDbTypeおよび.NETタイプの判断

この項では、`OracleParameter`クラス内の`System.Data.DbType`、`OracleDbType`および`Value`のプロパティからの判断を説明します。

`OracleParameter`クラスでは、`DbType`、`OracleDbType`および`Value`プロパティはリンクされています。これらのプロパティのいずれかに値を指定すると、残りの1つ以上のプロパティの値を推測できます。

#### OracleDbTypeからのDbTypeの判断

`OracleParameter`クラスでは、`OracleDbType`の値を指定すると、表3-8に示されているとおり`DbType`の値が判断されます。

表3-8 OracleDbTypeからのSystem.Data.DbTypeの判断

OracleDbType | System.Data.DbType
--- | ---
`Array` | `Object`
`BFile` | `Object`
`Blob` | `Object`
`BinaryFloat` | `Single`
`BinaryDouble` | `Double`
`Boolean` | `Boolean`
`Byte` | `Byte`
`Char` | `StringFixedLength`
`Clob` | `Object`
`Date` | `Date`
`Decimal` | `Decimal`
`Double` | `Double`
`Int16` | `Int16`
`Int32` | `Int32`
`Int64` | `Int64`
`IntervalDS` | `Object`
`IntervalYM` | `Int64`
`Long` | `String`
`LongRaw` | `Binary`
`NChar` | `StringFixedLength`
`NClob` | `Object`
`NVarchar2` | `String`
`Object` | `Object`
`Raw` | `Binary`
`Ref` | `Object`
`RefCursor` | `Object`
`Single` | `Single`
`TimeStamp` | `DateTime`
`TimeStampLTZ` | `DateTime`
`TimeStampTZ` | `DateTime`
`Varchar2` | `String`
`XmlType` | `String`

#### DbTypeからのOracleDbTypeの判断

`OracleParameter`クラスでは、`DbType`の値を指定すると、表3-9に示されているとおり`OracleDbType`の値が判断されます。

表3-9 DbTypeからのOracleDbTypeの判断

System.Data.DbType | OracleDbType
--- | ---
`Binary` | `Raw`
`Boolean` | `Boolean`
`Byte` | `Byte`
`Currency` | サポート対象外
`Date` | `Date`
`DateTime` | `TimeStamp`
`Decimal` | `Decimal`
`Double` | `Double`
`Guid` | サポート対象外
`Int16` | `Int16`
`Int32` | `Int32`
`Int64` | `Int64`
`Object` | `Object`
`Sbyte` | サポート対象外
`Single` | `Single`
`String` | `Varchar2`
`StringFixedLength` | `Char`
`Time` | `TimeStamp`
`UInt16` | サポート対象外
`UInt32` | サポート対象外
`Uint64` | サポート対象外
`VarNumeric` | サポート対象外

#### ValueからのDbTypeおよびOracleDbTypeの判断

`OracleParameter`クラスでは、`Value`は任意のNET Frameworkデータ型またはODP.NETタイプになるオブジェクト型です。`OracleParameter`クラスに`OracleDbType`プロパティおよび`DbType`プロパティが指定されていない場合、`OracleDbType`プロパティは`Value`プロパティのタイプから推測されます。

表3-10は、`Value`の型が.NET Frameworkデータ型の1つの場合における、`Value`プロパティからの`DbType`プロパティおよび`OracleDbType`プロパティの判断を示します。

表3-10 Value(.NETデータ型)からのDbTypeおよびOracleDbTypeの判断

Value(.NETデータ型) | System.Data.DbType | OracleDbType
--- | --- | ---
`Boolean` | `Boolean` | `Boolean`
`Byte` | `Byte` | `Byte`
`Byte[]` | `Binary` | `Raw`
`Char / Char []` | `String` | `Varchar2`
`DateTime` | `DateTime` | `TimeStamp`
`Decimal` | `Decimal` | `Decimal`
`Double` | `Double` | `Double`
`Float` | `Single` | `Single`
`Int16` | `Int16` | `Int16`
`Int32` | `Int32` | `Int32`
`Int64` | `Int64` | `Int64`
`IOracleCustomType` | `Object` | `Object`
`Single` | `Single` | `Single`
`String` | `String` | `Varchar2`
`TimeSpan` | Object | `IntervalDS`

注意:

`DbType`または`OracleDbType`プロパティを指定せずに、`OracleParameter`クラスの値としてその他の.NET Frameworkデータ型を使用すると、例外が発生します。これは、その他の.NET Frameworkデータ型からの`DbType`プロパティおよび`OracleDbType`プロパティの判断がサポートされていないためです。

表3-11は、`Value`の型が`Oracle.DataAccess.Types`の1つの場合における、`Value`プロパティからの`DbType`プロパティおよび`OracleDbType`プロパティの判断を示しています。

表3-11 Value(ODP.NETタイプ)からのDbTypeおよびOracleDbTypeの判断

Value(Oracle.DataAccess.Types) | System.Data.DbType | OracleDbType
--- | --- | ---
`OracleBFile` | `Object` | `BFile`
`OracleBinary` | `Binary` | `Raw`
`OracleBlob` | `Object` | `Blob`
`OracleBoolean` | `Boolean` | `Boolean`
`OracleClob` | `Object` | `Clob`
`OracleDate` | `Date` | `Date`
`OracleDecimal` | `Decimal` | `Decimal`
`OracleIntervalDS` | `Object` | `IntervalDS`
`OracleIntervalYM` | `Int64` | `IntervalYM`
`OracleRef` | `Object` | `Ref`
`OracleRefCursor` | `Object` | `RefCursor`
`OracleString` | `String` | `Varchar2`
`OracleTimeStamp` | `DateTime` | `TimeStamp`
`OracleTimeStampLTZ` | `DateTime` | `TimeStampLTZ`
`OracleTimeStampTZ` | `DateTime` | `TimeStampTZ`
`OracleXmlType` | `String` | `XmlType`

### PL/SQL連想配列バインド

ODP.NETは、PL/SQL連想配列(従来のPL/SQL索引付き表)バインドをサポートしています。

アプリケーションは、`OracleParameter`オブジェクトをPL/SQL連想配列としてPL/SQLストアド・プロシージャにバインドできます。次の`OracleParameter`プロパティは、この機能に使用されます。

- `CollectionType`

  このプロパティは、PL/SQL連想配列にバインドするために、`OracleCollectionType.PLSQLAssociativeArray`に設定する必要があります。

- `ArrayBindSize`

  このプロパティは、固定長の要素タイプ(`Int32`など)の場合は無視されます。

  可変長の要素タイプ(`Varchar2`など)の場合、`ArrayBindSize`プロパティ内の各要素は、`Value`プロパティ内の対応する要素のサイズを指定します。

  `Output`パラメータ、`InputOutput`パラメータおよび戻り値の場合、このプロパティは、可変長の変数に対して指定する必要があります。

  ODP.NETの各配列要素には、1つの要素ごとに文字を2GBまで格納でき、バイナリ・データの場合は4GBまで格納できます。

- `ArrayBindStatus`

  このプロパティは、`OracleParameter.Value`プロパティ内の各要素の実行ステータスを指定します。

- `Size`

  このプロパティは、PL/SQL連想配列にバインドされる要素の最大数を指定します。

- `値`

  このプロパティは、値の配列に`NULL`または`DBNull.Value`を設定する必要があります。

ODP.NETはPL/SQL連想配列のバインド・パラメータをサポートしており、PL/SQL連想配列には次のデータ型があります。

- `BINARY_FLOAT`

- `CHAR`

- `DATE`

- `NCHAR`

- `NUMBER`

- `NVARCHAR2`

- `RAW`

- `ROWID`

- `UROWID`

- `VARCHAR2`

連想配列でサポートされていないデータ型を使用するとORA-600エラーが発生する場合があります。

PL/SQL連想配列の例

この例では、3つの`OracleParameter`オブジェクトをPL/SQL連想配列としてバインドします。`Param1`は`In`パラメータ、`Param2`は`InputOutput`パラメータ、`Param3`は`Output`パラメータとしてバインドします。

PL/SQLパッケージ:MYPACK

    /* Setup the tables and required PL/SQL:

       connect scott/tiger@oracle
       CREATE TABLE T1(COL1 number, COL2 varchar2(20));

       CREATE or replace PACKAGE MYPACK AS
         TYPE AssocArrayVarchar2_t is table of VARCHAR(20) index by BINARY_INTEGER;
         PROCEDURE TestVarchar2(
           Param1 IN     AssocArrayVarchar2_t,
           Param2 IN OUT AssocArrayVarchar2_t,
           Param3    OUT AssocArrayVarchar2_t);
         END MYPACK;
    /

       CREATE or REPLACE package body MYPACK as
         PROCEDURE TestVarchar2(
           Param1 IN     AssocArrayVarchar2_t,
           Param2 IN OUT AssocArrayVarchar2_t,
           Param3    OUT AssocArrayVarchar2_t)
         IS
         i integer;
         BEGIN
           -- copy a few elements from Param2 to Param1\n
           Param3(1) := Param2(1);
           Param3(2) := NULL;
           Param3(3) := Param2(3);
           -- copy all elements from Param1 to Param2\n
           Param2(1) := Param1(1);
           Param2(2) := Param1(2);
           Param2(3) := Param1(3);
           -- insert some values to db\n
           FOR i IN 1..3 LOOP
             insert into T1 values(i,Param2(i));
           END LOOP;
         END TestVarchar2;
       END MYPACK;
    /
     */

    // C#

    using System;
    using System.Data;
    using Oracle.DataAccess.Client;

    class AssociativeArraySample
    {
      static void Main()
      {
        OracleConnection con = new OracleConnection();

        con.ConnectionString = "User Id=scott;Password=tiger;Data Source=oracle";
        con.Open();
        Console.WriteLine("Connected to Oracle" + con.ServerVersion);

        OracleCommand cmd = new OracleCommand(
          "begin MyPack.TestVarchar2(:1, :2, :3); end;", con);

        OracleParameter Param1 = cmd.Parameters.Add("1", OracleDbType.Varchar2);
        OracleParameter Param2 = cmd.Parameters.Add("2", OracleDbType.Varchar2);
        OracleParameter Param3 = cmd.Parameters.Add("3", OracleDbType.Varchar2);

        Param1.Direction = ParameterDirection.Input;
        Param2.Direction = ParameterDirection.InputOutput;
        Param3.Direction = ParameterDirection.Output;

        // Specify that we are binding PL/SQL Associative Array
        Param1.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
        Param2.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
        Param3.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

        // Setup the values for PL/SQL Associative Array
        Param1.Value = new string[3] {
          "First Element", "Second Element ", "Third Element "
        };
        Param2.Value = new string[3] {
          "First Element", "Second Element ", "Third Element "
        };
        Param3.Value = null;

        // Specify the maximum number of elements in the PL/SQL Associative Array
        Param1.Size = 3;
        Param2.Size = 3;
        Param3.Size = 3;

        // Setup the ArrayBindSize for Param1
        Param1.ArrayBindSize = new int[3] { 13, 14, 13 };

        // Setup the ArrayBindStatus for Param1
        Param1.ArrayBindStatus = new OracleParameterStatus[3] {
          OracleParameterStatus.Success, OracleParameterStatus.Success,
          OracleParameterStatus.Success};

        // Setup the ArrayBindSize for Param2
        Param2.ArrayBindSize = new int[3] { 20, 20, 20 };

        // Setup the ArrayBindSize for Param3
        Param3.ArrayBindSize = new int[3] { 20, 20, 20 };

        // execute the cmd
        cmd.ExecuteNonQuery();

        //print out the parameter's values
        Console.WriteLine("parameter values after executing the PL/SQL block");
        for (int i = 0; i < 3; i++)
          Console.WriteLine("Param2[{0}] = {1} ", i,
            (cmd.Parameters[1].Value as Array).GetValue(i));

        for (int i = 0; i < 3; i++)
          Console.WriteLine("Param3[{0}] = {1} ", i,
            (cmd.Parameters[2].Value as Array).GetValue(i));

        // Close and Dispose OracleConnection object
        con.Close();
        con.Dispose();
        Console.WriteLine("Disconnected");
      }
    }

### 配列バインド

配列バインド機能を使用すると、アプリケーションでは、`OracleParameter`クラスを使用してタイプの配列をバインドできます。配列バインド機能を使用すると、アプリケーションは、1回のデータベース・ラウンドトリップで複数の行を表に挿入できます。

次のコード例は、1回のデータベース・ラウンドトリップで3行を`Dept`表に挿入します。`OracleCommand` `ArrayBindCount`プロパティは、文の実行時に使用する配列の要素の数を定義します。

    // C#

    using System;
    using System.Data;
    using Oracle.DataAccess.Client;

    class ArrayBindSample
    {
      static void Main()
      {
        OracleConnection con = new OracleConnection();
        con.ConnectionString = "User Id=scott;Password=tiger;Data Source=oracle;";
        con.Open();
        Console.WriteLine("Connected successfully");

        int[] myArrayDeptNo = new int[3] { 10, 20, 30 };
        OracleCommand cmd = new OracleCommand();

        // Set the command text on an OracleCommand object
        cmd.CommandText = "insert into dept(deptno) values (:deptno)";
        cmd.Connection = con;

        // Set the ArrayBindCount to indicate the number of values
        cmd.ArrayBindCount = 3;

        // Create a parameter for the array operations
        OracleParameter prm = new OracleParameter("deptno", OracleDbType.Int32);

        prm.Direction = ParameterDirection.Input;
        prm.Value = myArrayDeptNo;

        // Add the parameter to the parameter collection
        cmd.Parameters.Add(prm);

        // Execute the command
        cmd.ExecuteNonQuery();
        Console.WriteLine("Insert Completed Successfully");

        // Close and Dispose OracleConnection object
        con.Close();
        con.Dispose();
      }
    }

関連項目:

詳細は、Valueを参照してください

#### OracleParameterの配列バインド・プロパティ

`OracleParameter`クラスは、配列バインド機能を使用するときに、詳細な制御を行うために2つのプロパティを提供します。

- `ArrayBindSize`

  `ArrayBindSize`プロパティは、配列内の対応する各値の最大サイズを指定する整数の配列です。`ArrayBindSize`プロパティは、`OracleParameter`オブジェクトの`Size`プロパティに類似していますが、`ArrayBindSize`プロパティは配列内の各値のサイズを指定するという点が異なります。

  アプリケーションは、実行前に`ArrayBindSize`プロパティを移入する必要があります。ODP.NETは、実行後にArrayBindSizeプロパティを移入します。

  `ArrayBindSize`プロパティは、`Clob`、`Blob`、`Varchar2`など、可変長のパラメータ・タイプにのみ使用されます。Unicode文字列タイプのバイナリ・データ型および文字の場合、サイズはバイトで表されます。文字列タイプのカウントには、終了文字は含まれません。サイズが明示的に設定されていない場合は、値の実際のサイズから推測されます。出力パラメータの場合、各値のサイズはODP.NETにより設定されます。固定長のデータ型の場合、`ArrayBindSize`プロパティは無視されます。

  文字でもバイナリ・データでも、最大`ArrayBindSize`サイズは`2GB`です。

- `ArrayBindStatus`

  `ArrayBindStatus`プロパティは、パラメータの配列内の対応する各値のステータスを指定する`OracleParameterStatus`値の配列です。このプロパティは、`OracleParameter`の`Status`プロパティに類似していますが、`ArrayBindStatus`プロパティは配列内の各値のステータスを指定するという点が異なります。

  アプリケーションは、実行前に`ArrayBindStatus`プロパティを移入する必要があります。ODP.NETは、実行後に移入します。`ArrayBindStatus`プロパティを使用するアプリケーションは、実行前に、パラメータの配列内の対応する要素に`NULL`値を指定できます。ODP.NETは、実行後に`ArrayBindStatus`プロパティを移入して、配列内の対応する要素に`NULL`値があるか、または値がフェッチされたときにデータの切捨てが発生したかどうかを示します。

#### 配列バインドのエラー処理

配列バインドの実行中にエラーが発生した場合、`Value`プロパティ内のどの要素がエラーの原因になったかを判断するのは困難です。ODP.NETは、エラーが発生した行を判断する方法を提供することで、エラーの原因になった行の要素を簡単に検索できるようにします。

配列バインドの実行中に`OracleException`オブジェクトがスローされた場合、`OracleErrorCollection`には1つ以上の`OracleError`オブジェクトが含まれます。これらの`OracleError`オブジェクトはそれぞれ、実行中に発生した個別のエラーを表し、プロバイダ固有のプロパティ`ArrayBindIndex`を含みます。

次に配列バインドのエラー処理の例を示します。

    /* Database Setup
    connect scott/tiger@oracle
    drop table depttest;
    create table depttest(deptno number(2));
    */

    // C#

    using System;
    using System.Data;
    using Oracle.DataAccess.Client;

    class ArrayBindExceptionSample
    {
      static void Main()
      {
        OracleConnection con = new OracleConnection();
        con.ConnectionString = "User Id=scott;Password=tiger;Data Source=oracle;";
        con.Open();

        OracleCommand cmd = new OracleCommand();

        // Start a transaction
        OracleTransaction txn = con.BeginTransaction(IsolationLevel.ReadCommitted);

        try
        {
          int[] myArrayDeptNo = new int[3] { 10, 200000, 30 };
          // int[] myArrayDeptNo = new int[3]{ 10,20,30};

          // Set the command text on an OracleCommand object
          cmd.CommandText = "insert into depttest(deptno) values (:deptno)";
          cmd.Connection = con;

          // Set the ArrayBindCount to indicate the number of values
          cmd.ArrayBindCount = 3;

          // Create a parameter for the array operations
          OracleParameter prm = new OracleParameter("deptno", OracleDbType.Int32);

          prm.Direction = ParameterDirection.Input;
          prm.Value = myArrayDeptNo;

          // Add the parameter to the parameter collection
          cmd.Parameters.Add(prm);

          // Execute the command
          cmd.ExecuteNonQuery();
        }
        catch (OracleException e)
        {
          Console.WriteLine("OracleException {0} occured", e.Message);
          if (e.Number == 24381)
            for (int i = 0; i < e.Errors.Count; i++)
              Console.WriteLine("Array Bind Error {0} occured at Row Number {1}",
                e.Errors[i].Message, e.Errors[i].ArrayBindIndex);

          txn.Commit();
        }
        cmd.Parameters.Clear();
        cmd.CommandText = "select count(*) from depttest";

        decimal rows = (decimal)cmd.ExecuteScalar();

        Console.WriteLine("{0} row have been inserted", rows);
        con.Close();
        con.Dispose();
      }
    }

関連項目:

詳細は、ArrayBindIndexを参照してください。

#### OracleParameterStatusの列挙型

表3-12に、`OracleParameterStatus`の列挙値をリストします。

表3-12 OracleParameterStatusのメンバー

メンバー名 | 説明
--- | ---
`Success` | 入力パラメータの場合、入力値が列に割り当てられたことを示します。 出力パラメータの場合、プロバイダによってそのままの値がパラメータに割り当てられたことを示します。
`NullFetched` | `NULL`値が列または`OUT`パラメータからフェッチされたことを示します。
`NullInsert` | `NULL`値が列に挿入されることを示します。
`Truncation` | 列からデータをフェッチする際に切捨てが行われたことを示します。

## バッチ処理

`OracleDataAdapter.Update`メソッドがコールされると、`OracleDataAdapter` `UpdateBatchSize`プロパティではバッチ処理が有効になります。`UpdateBatchSize`は、各ラウンドトリップで、Oracle Databaseを更新するDataSet行数を示す数値プロパティです。

これにより、開発者はデータベースへのラウンド・トリップの回数を削減できます。

関連項目:

UpdateBatchSize

## 文キャッシング

文キャッシングにより、最初の実行で作成されたサーバー・カーソルのキャッシングによる実行の前に、各SQL文またはPL/SQL文を解析する必要がなくなります。同じ文を後で実行する場合、カーソルから解析された情報を再利用して、文を解析せずに実行することで、パフォーマンスが向上します。

文キャッシングによるパフォーマンスの向上を得るために、繰り返し実行される文のみをキャッシュすることをお薦めします。さらに、SQL文またはPL/SQL文では、リテラル値ではなくパラメータを使用してください。これにより、文キャッシングが有効になります。これは、後続の実行でパラメータ値が異なる場合でも、パラメータ化された文から解析された情報は再利用できるためです。ただし、文のリテラル値が異なる場合、解析された情報は、後続の文にも同じリテラル値がないかぎり、再使用できません。

### 文キャッシングの接続文字列属性

次の接続文字列属性は、ODP.NET文キャッシング機能の動作を制御します。

- `Statement` `Cache` `Size`

  この属性は、ODP.NET文キャッシングを有効化または無効化します。デフォルトでは、この属性は`0`(無効)に設定されます。`0`より大きい値に設定すると、ODP.NET文キャッシングが有効になり、指定された値は接続用にキャッシュできる文の最大数として使用されます。指定された最大キャッシュ・サイズまで接続がキャッシュされると、最低使用頻度のカーソルが解放され、新しく作成されたカーソルをキャッシュするためのスペースが確保されます。

  自動チューニングを有効にすると、文キャッシングも有効になります。その場合、`Statement Cache Size`は自動的に構成されます。

- `Statement` `Cache` `Purge`

  この属性は、接続がクローズされた場合、または接続プールに戻された場合にキャッシュされるすべての文を消去する方法を提供します。デフォルトでは、この属性は`false`に設定されています。つまり、接続がプールに戻されてもカーソルは解放されません。

### レジストリを使用した文キャッシングの有効化

アプリケーションを変更せずに、システムで実行しているすべてのODP.NETアプリケーションの文キャッシングをデフォルトで有効化するには、`HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\ODP.NET\``Assembly_Version` `\StatementCacheSize`のレジストリ・キーを`0`より大きい値に設定します。この値は、サーバーでキャッシュされるカーソルの数を指定します。

システムのデフォルト値は、接続プール・レベルで無視できます。`Statement` `Cache` `Size`属性は、レジストリ値とは異なるサイズに設定するか、無効にできます。`Statement` `Cache` `Size`は、XML構成ファイルで設定することもできます。

関連項目:

詳細は、「Oracle Data Provider for .NETの構成」を参照してください。

### 文キャッシングのメソッドおよびプロパティ

次のプロパティおよびメソッドは、文キャッシングが有効な場合のみ当てはまります。

- `OracleCommand.AddToStatementCache`プロパティ

  文キャッシングが有効な場合、このプロパティを`true`に設定すると、文の実行時にキャッシュに文が追加されます。デフォルトでは、このプロパティはtrueに設定されています。文キャッシングが無効な場合、またはこのプロパティが`false`に設定されている場合、実行された文はキャッシュされません。

- `OracleConnection.PurgeStatementCache`メソッド

  このメソッドは、特定の接続に関連付けられたデータベースでオープンしているカーソルをすべてクローズすることで、キャッシュされた文をすべて消去します。このコールの後も、文キャッシングは有効です。

### 接続と文キャッシング

文キャッシングは、接続ごとに個別に管理されます。このため、異なる接続で同じ文を実行するには、接続ごとに1回消去して、接続ごとに個別のカーソルをキャッシュする必要があります。

### プーリングと文キャッシング

プーリングと文キャッシングは同時に使用できます。接続プーリングが有効で、`Statement` `Cache` `Purge`属性が`false`に設定されている場合、個別の接続で実行される文は、プールされた接続の存続期間を通じてキャッシュされます。

`Statement` `Cache` `Purge`属性が`true`に設定されている場合は、接続がプールに戻されたときに、キャッシュされたすべてのカーソルが解放されます。接続プーリングが無効な場合、カーソルは接続の存続中にキャッシュされますが、`OracleConnection`オブジェクトがクローズまたは処理されたときにはクローズされます。

## 自動チューニング

ODP.NETアプリケーションの自動チューニングを行ってパフォーマンスを最適化することができます。ODP.NETは実行時のアプリケーション問合せを動的に監視します。

注意:

`Pooling`接続文字列属性が`false`に設定されている場合、アプリケーションの自動チューニングは実行されません。また、自動チューニングは.NETストアド・プロシージャではサポートされません。

文キャッシュ・サイズ(StatementCacheSize)は、アプリケーションによって実行される文を監視することで自動的にチューニングされます。次の各項では、アプリケーションの自動チューニングについて説明します。

- 文キャッシングの自動チューニング

- アプリケーションの自動チューニングの有効化または無効化

- 最適化のための変更のトレース

### 文キャッシングの自動チューニング

文キャッシングを使用すると、各SQL文またはPL/SQL文を実行前に再解析する必要がなくなり、パフォーマンスが向上します。

アプリケーションの自動チューニングが有効な場合、ODP.NETは文キャッシュ・サイズの最適な値を決定するためにアプリケーションの動作を継続的に監視します。接続文字列、構成ファイルまたはレジストリに指定した文キャッシュ・サイズの値は無視されます。

アプリケーションが最初に初期化されるときは、文キャッシュ・サイズのデフォルト値が使用されます。アプリケーションが文を実行するのと並行して、ODP.NETは文キャッシュ・サイズの値の自動チューニングに使用される統計を収集します。文キャッシュ・サイズの自動チューニングを行うとパフォーマンスが向上します。

注意:

文キャッシングの利点を最大限活用するには、文の実行ごとに異なるインライン値で文を動的に生成しないでください。かわりに、パラメータ化されたコマンドを使用して、実行およびキャッシュする必要がある一意の文の数を最小限にします。これは、パラメータ値や文の実行回数にかかわらず、一意の各コマンド・テキストでキャッシュする必要のある文が1つのみになるためです。

接続ごとにキャッシュできる文の最大数は、`MaxStatementCacheSize`構成属性によって決まります。`MaxStatementCacheSize`の値は、WindowsレジストリまたはXML構成ファイルで指定できます。

`MaxStatementCacheSize`設定は、キャッシュされる文の数やオープンしているカーソル数を制限する場合に便利です。これは、キャッシュされる文は、サーバーでオープンになっているカーソルと等しいためです。このため、`MaxStatementCacheSize`をデータベースの`MAX_OPEN_CURSORS`設定よりも大きい値に設定しないでください。

`MaxStatementCacheSize`構成属性を構成するには、次のWindowsレジストリ・キーを使用します。

    HKLM\Software\Oracle\ODP.NET\version\MaxStatementCacheSize

`MaxStatementCacheSize`キーの種類は`REG_SZ`です。これは、0から`System.Int32.MaxValue`の整数値に設定できます。

次の例では、ADO.NET 2.0以上の構成ファイルで`MaxStatementCacheSize`プロパティを設定しています。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <oracle.dataaccess.client>
        <settings>
          <add name="MaxStatementCacheSize" value="300"/>
        </settings>
      </oracle.dataaccess.client>
    </configuration>

アプリケーションの自動チューニングが無効な場合、文キャッシュ・サイズの値は接続文字列、構成ファイルまたはレジストリの設定によって決まります。これらのソースのいずれにも文キャッシュ・サイズが指定されていない場合、文キャッシュ・サイズのデフォルト値は0に設定されます。旧リリースのODP.NETと同じデフォルト設定でODP.NETを構成するには、自動チューニングを無効化し、`StatementCacheSize`値を10に設定します。

関連項目:

文キャッシング

### アプリケーションの自動チューニングの有効化または無効化

ODP.NETアプリケーションの自動チューニングはデフォルトで有効になっています。アプリケーションの自動チューニングを有効化または無効化するには、次のいずれかの方法を使用します。

- 自動チューニングの接続文字列属性

  `Self Tuning`接続文字列属性を変更すると、特定の接続プールについてアプリケーションの自動チューニングを有効化または無効化できます。`Self Tuning`のデフォルト値は`true`です。

- Windowsレジストリ

  次のレジストリ・エントリを変更すると、ODP.NETの特定のバージョンについてアプリケーションの自動チューニングを有効化または無効化できます。

      HKLM\Software\Oracle\ODP.NET\version\SelfTuning

  `SelfTuning`キーの種類は`REG_SZ`です。`1`(有効)または`0`(無効)に設定できます。

- 構成ファイル

  アプリケーション構成ファイル(`app.config`)またはWeb構成ファイル(`web.config`)を変更すると、ODP.NETアプリケーションの自動チューニングを有効化または無効化できます。

  次の例は、ADO.NET 2.0.xのアプリケーション構成ファイルで自動チューニングを有効化する方法を示しています。

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        <oracle.dataaccess.client>
          <settings>
            <add name="SelfTuning" value="1"/>
          </settings>
        </oracle.dataaccess.client>
      </configuration>

  注意:

  アプリケーションの最適な文キャッシュ・サイズがわかっている場合、自動チューニングを無効化して、レジストリ、構成ファイルまたはアプリケーションで`StatementCacheSize`を最適な値に設定できます。自動チューニングが無効化されていて、`StatementCacheSize`がまったく設定されていない場合、`StatementCacheSize`にはデフォルト値の0が使用されます。

### 最適化のための変更のトレース

自動チューニングによる最適化のための変更をアプリケーションでトレースできます。`StatementCacheSize`に加えられたすべての変更がトレースされます。エラーがあれば、それもトレースされます。

自動チューニングのトレースに使用される`TraceLevel`は`64`です。

関連項目:

`TraceLevel`値の詳細は、表2-2を参照