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

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

前 | 次 |

# 暗黙的なREF CURSORのバインド

ODP.NETでは、.NETコードに`REF CURSOR`パラメータを明示的にバインドせずに、このパラメータを使用するストアド・プロシージャをアプリケーションで実行できます。ODP.NET管理対象外ドライバと管理対象ドライバは、.NET構成ファイルで実行される構成を通じて、`REF CURSOR`の暗黙的なバインディングをサポートします。

読取り専用の結果セット(`OracleDataReader`を使用する`REF CURSOR`など)では、`REF CURSOR`のスキーマ情報が自動的に取得されます。

更新可能な`REF CURSOR`やEntity Frameworkを使用する場合など、開発者は、アプリケーションで暗黙的な`REF CURSOR`をバインドできるように、`REF CURSOR`のスキーマ情報を定義する必要のある場合があります。Entity Frameworkアプリケーションでは、暗黙的な`REF CURSOR`のバインドを使用して、`REF CURSOR`データから複合型がインスタンス化されます。アプリケーションの`app.config`、`web.config`または`machine.config` .NET構成ファイルで、`REF CURSOR`のバインド情報およびメタデータ情報を指定する必要があります。

.NET構成ファイルで指定した属性は、`REF CURSOR`を表す`OracleDataReader`オブジェクトからスキーマ情報をリクエストする際にも使用されます。これは、`SELECT`を使用して単一表から作成される`REF CURSOR`について、`OracleDataAdapter`および`OracleCommandBuilder`を使用してその表を更新できることを意味します。

Entity Frameworkを使用する際は、関数インポートによって、明示的にバインドされた`REF CURSOR`が戻されます。`REF CURSOR`は、複合型またはエンティティ型の集合として戻されます。複合型の集合を戻すには、.NET構成ファイルで`REF CURSOR`のバインド情報およびメタデータ情報を定義する必要があります。エンティティ型の集合を戻すには、.NET構成ファイルでバインド情報のみを定義する必要があります。

この項には次のトピックが含まれます:

- .NET構成ファイルでのREF CURSORのバインド情報およびメタデータ情報の指定

- 構成ファイルおよびアプリケーションのサンプル

- 使用上の考慮事項

## .NET構成ファイルでのREF CURSORのバインド情報およびメタデータ情報の指定

`REF CURSOR`の情報は、.NET構成ファイルの`oracle.dataacccess.client`構成セクションで指定します。各情報に対して`<add>`要素を使用します。`add`要素では、`name`-`value`属性を使用して`REF CURSOR`の情報を指定します。バインド情報を指定するには、次のフォーマットを使用します。

    <add name="SchemaName.PackageName.StoredProcedureName.RefCursor.RefCursorParameterPositionOrName"
    value="implicitRefCursor bindinfo='mode=InputOutput|Output|ReturnValue'" />

メタデータ情報を指定するには、次のフォーマットを使用します。

    <add name="SchemaName.PackageName.StoredProcedureName.RefCursorMetaData.RefCursorParameterPositionorName.Column.ColumnOrdinal"
    value="implicitRefCursor metadata=AttributesList" />

`add`要素は、`REF CURSOR`の各列に対して定義する必要があります。たとえば、5つの列を返す`REF CURSOR`では、構成ファイルで5つの`add`要素を定義する必要があります。

各`add`要素には、`name`属性および`value`属性が含まれます。`value`属性は、`implicitRefCursor`で始まり、次にバインド情報またはメタデータ情報を指定するための`bindinfo`属性または`metadata`属性が続く必要があります。

`bindinfo`情報は、ODP.NETで、`REF CURSOR`パラメータのバインドに使用されます。`metadata`情報は、ODP.NETで、スキーマ情報を適切な`REF CURSOR`と関連付けるために使用されます。メタデータは、パラメータとその値を含む属性リストで構成されます。

`SchemaName`、`PackageName`および`StoredProcedureName`では、大/小文字が区別されます。暗黙的な`REF CURSOR`のバインドを使用するストアド・プロシージャを実行するには、`name`属性の`SchemaName``.``PackageName``.``StoredProcedureName`が、そのストアド・プロシージャのデータ・ディクショナリに指定されている名前と完全に一致している必要があります。

注意:

Entity Framework外で暗黙的な`REF CURSOR`のバインド機能を使用する場合は、.NET構成ファイルおよび`OracleCommand CommandText` で、ストアド・プロシージャ名の前にスキーマ名が連結されている必要がありません。

データベースのスキーマ名、パッケージ名またはストアド・プロシージャ名に小文字が含まれる場合は、小文字が保持されるように、構成ファイルで名前を二重引用符(`"`)で囲む必要があります。`name`属性内で二重引用符を使用する必要がある場合は、`&quot;`を使用します。たとえば、データベースのスキーマ名が`HrSchema`、パッケージ名が`HrPackage`、ストアド・プロシージャ名が`HrStoredProcedure`である場合、構成ファイルには次を使用する必要があります。

    <add name="&quot;HrSchema&quot;.&quot;HrPackage&quot;.&quot;HrStoredProcedure&quot;.RefCursorMetaData . . . />

デフォルトで、これらの名前はOracle Databaseに大文字で格納されます。ODP.NETではデフォルトの動作が想定されるため、二重引用符を使用して明示的に小文字を保持しないかぎり、すべての名前が大文字に変換されます。

注意:

`SchemaName`、`PackageName`、`StoredProcedureName`または`ParameterName`は、名前にピリオド(「`.`」)を含むことができません。たとえば、`P.0`はパラメータ名として許可されません。

名前属性の`RefCursorParameterPositionOrName`は、名前指定によるバインドと位置指定によるバインドのいずれを使用するかに基づいて、パラメータ位置(位置指定によるバインドの場合)またはパラメータ名(名前指定によるバインドの場合)に適切に設定する必要があります。ファンクションでは、位置は0ベースであり、位置0は戻り値を表します。プロシージャでは、戻り値が存在しないため、位置は1ベースです。たとえば、ストアド・プロシージャで5つのパラメータが許可され、3番目と5番目のパラメータ位置にある2つの`REF CURSOR`のみが返される場合、.NET config `REF CURSOR`のバインド情報には、位置3に1つと位置5に1つのエントリが含まれます。

名前によるバインドを使用する場合は、属性名によって`REF CURSOR`パラメータを識別します。`name`には、そのストアド・プロシージャのデータ・ディクショナリで指定されている名前と同じ名前を、大/小文字を区別して使用する必要があります。

`bindinfo`で、`mode`はパラメータのディレクションを指定します。モードは、`InputOutput`、`Output`、`ReturnValue`のいずれかである必要があります。

注意:

入力パラメータとしての`REF CURSOR`については、暗黙的な`REF CURSOR`のバインドがサポートされていません。

`mode`が`Input`に設定されている`REF CURSOR`のエントリが.NET構成ファイルに含まれる場合は、実行時に例外がスローされます。

`metadata`では、`AttributesList`にパラメータのリストが含まれます。表3-18に、`AttributesList`に含むことのできるパラメータを示します。

例3-5に、`bindinfo`を使用する`add`要素のサンプルを示します。ここで、スキーマ名は`SCOTT`で、ストアド・プロシージャ名は`TESTPROC`です。パラメータ名は`parameter1`です。モードは`output`です。

例3-6に、`metadata`を使用する`add`要素のサンプルを示します。

表3-18 属性リストで許可されるパラメータ

名前 | Type | Entity Frameworkで必須/オプション | 説明
--- | --- | --- | ---
`ColumnName` | `System.String` | 必須 | 列の名前です。
`ProviderType` | `Oracle.DataAccess.Client.OracleDbType` | 必須 | 列のデータベース列タイプ(`OracleDbType`)
`NativeDataType` | `System.String` | 必須 | Oracleタイプ。たとえば、`NCLOB`です。
`BaseColumnName` | `System.String` | オプション | 列に別名が使用されている場合の、データベース内の列名。
`BaseSchemaName` | `System.String` | オプション | 列を含むデータベース内のスキーマ名。
`BaseTableName` | `System.String` | オプション | 列を含むデータベース内の表名またはビュー名。
`ColumnSize` | `System.Int64` | オプション | 列内の値として可能な最大長
`NumericPrecision` | `System.Int16` | オプション | 列が数値のデータ型の場合の、列の最大精度。
`NumericScale` | `System.Int16` | オプション | 列が数値のデータ型の場合の、列の最大スケール。
`IsUnique` | `System.Boolean` | オプション | 列値が一意かどうかを示します。
`IsKey` | `System.Boolean` | オプション | 列がキー列かどうかを示します。`REF CURSOR`の情報を使用して更新する表では、`REF CURSOR`メタデータの1つ以上の列で、この値が`true`に設定されている必要があります
`IsRowID` | `System.Boolean` | オプション | 列が`ROWID`の場合は`true`、それ以外の場合は`false`。
`DataType` | `System.RuntimeType` | オプション | 共通言語のランタイム型にマップします。
`AllowDBNull` | `System.Boolean` | オプション | null値が許可されている場合は`true`、それ以外の場合は`false`
`IsAliased` | `System.Boolean` | オプション | 列が別名の場合は`true`、それ以外の場合は`false`。
`IsByteSemantic` | `System.Boolean` | オプション | `IsByteSemantic`の場合は次のとおりです。 `ColumnSize`値にバイト・セマンティクスが使用されている場合は`true` `ColumnSize`にキャラクタ・セマンティクスが使用されている場合は`false`
`IsExpression` | `System.Boolean` | オプション | 列が式の場合は`true`、それ以外の場合は`false`。
`IsHidden` | `System.Boolean` | オプション | 列が非表示の場合は`true`、それ以外の場合は`false`。
`IsReadOnly` | `System.Boolean` | オプション | 列が読取り専用の場合は`true`、それ以外の場合は`false`
`IsLong` | `System.Boolean` | オプション | `true`(列が`LONG``、LONG RAW、BLOB、CLOB` または `BFILE`型の場合)、`false`(それ以外の場合)。
`UdtTypeName` | `System.String` | オプション | UDTのタイプ名。
`ProviderDBType` | `System.Data.DbType` | オプション | `System.Data.DbType`
`ObjectName` | `System.String` | オプション | オブジェクトの名前を表します。

表3-18にリストされている一部の属性については、結果セットのメタデータを使用して、値が自動的に設定されます。開発者は、明示的に値を設定して、デフォルトの値を上書きできます。

特定の操作でオプションとしてリストされている一部の属性について、明示的に定義する必要のある場合があります。たとえば、更新可能な`REF CURSOR`では、キー情報を定義する必要があります。

例3-5 bindinfoを含むadd要素の使用

    <add name="SCOTT.TESTPROC.RefCursor.parameter1" value="implicitRefCursor
     bindinfo='mode=Output'" />

例3-6 メタデータを含むadd要素の使用

    <add name="scott.TestProc.RefCursorMetaData.parameter1.Column.0"
    value="implicitRefCursor metadata='ColumnName=EMPNO;BaseColumnName=EMPNO;
    BaseSchemaName=SCOTT;BaseTableName=EMP;NativeDataType=number;
    ProviderType=Int32;DataType=System.Int32;ColumnSize=4;AllowDBNull=false;
    IsKey=true'" />

## 構成ファイルおよびアプリケーションのサンプル

この項では、サンプル・アプリケーションを構築して、暗黙的な`REF CURSOR`のバインドを説明します。この章の内容は、次のとおりです。

- ストアド・プロシージャおよびストアド・ファンクションのサンプル

- アプリケーション構成ファイルのサンプル

- 構成ファイルを使用するアプリケーションのサンプル

ストアド・プロシージャおよびストアド・ファンクションのサンプル

    CREATE OR REPLACE FUNCTION GETEMP (
      EMPID IN NUMBER) return sys_refcursor is
      emp sys_refcursor;
    BEGIN
      OPEN emp FOR SELECT empno, ename FROM emp where empno = EMPID;
      return emp;
    END;
    /

    CREATE OR REPLACE PROCEDURE "GetEmpAndDept" (
      EMPS OUT sys_refcursor,
      DEPTS OUT sys_refcursor) AS
    BEGIN
      OPEN EMPS for SELECT empno, ename from emp;
      OPEN DEPTS for SELECT deptno, dname from dept;
    END;
    /

アプリケーション構成ファイルのサンプル

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <oracle.dataaccess.client>
        <settings>

          <!-- The following is for SCOTT.GETEMP -->
          <add name="SCOTT.GETEMP.RefCursor.0"
               value="implicitRefCursor bindinfo='mode=ReturnValue'" />

          <!-- The following is for SCOTT.GETEMP's REF CURSOR metadata -->
          <add name="SCOTT.GETEMP.RefCursorMetaData.0.Column.0"
               value="implicitRefCursor metadata='ColumnName=EMPNO;
               BaseColumnName=EMPNO;BaseSchemaName=SCOTT;BaseTableName=EMP;
               NativeDataType=number;ProviderType=Int32;ProviderDBType=Int32;
               DataType=System.Int32;ColumnSize=4;NumericPrecision=10;
               NumericScale=3;AllowDBNull=false;IsKey=true'" />

          <add name="SCOTT.GETEMP.RefCursorMetaData.0.Column.1"
               value="implicitRefCursor metadata='ColumnName=ENAME;
               BaseColumnName=ENAME;BaseSchemaName=SCOTT;BaseTableName=EMP;
               NativeDataType=varchar2;ProviderType=Varchar2;
               ProviderDBType=String;DataType=System.String;
               ColumnSize=10;AllowDBNull=true'" />

          <!-- The following is for "SCOTT"."GetEmpAndDept" -->
          <add name="SCOTT.&quot;GetEmpAndDept&quot;.RefCursor.EMPS"
               value="implicitRefCursor bindinfo='mode=Output'" />

          <!-- The following is for SCOTT.GETEMP's EMPS REF CURSOR metadata -->
          <add name="SCOTT.&quot;GetEmpAndDept&quot;
               .RefCursorMetaData.EMPS.Column.0"
               value="implicitRefCursor metadata='ColumnName=EMPNO;
               BaseColumnName=EMPNO;BaseSchemaName=SCOTT;BaseTableName=EMP;
               NativeDataType=number;ProviderType=Int32;ProviderDBType=Int32;
               DataType=System.Int32;ColumnSize=4;NumericPrecision=10;
               NumericScale=3;AllowDBNull=false;IsKey=true'" />

          <add name="SCOTT.&quot;GetEmpAndDept&quot;
               .RefCursorMetaData.EMPS.Column.1"
               value="implicitRefCursor metadata='ColumnName=ENAME;
               BaseColumnName=ENAME;BaseSchemaName=SCOTT;BaseTableName=EMP;
               NativeDataType=varchar2;ProviderType=Varchar2;
               ProviderDBType=String;DataType=System.String;
               ColumnSize=10;AllowDBNull=true'" />

          <!-- The following is for SCOTT.GETEMP's DEPTS REF CURSOR metadata -->
          <add name="SCOTT.&quot;GetEmpAndDept&quot;.RefCursor.DEPTS"
               value="implicitRefCursor bindinfo='mode=Output'" />

          <add name="SCOTT.&quot;GetEmpAndDept&quot;
               .RefCursorMetaData.DEPTS.Column.0"
               value="implicitRefCursor metadata='ColumnName=DEPTNO;
               BaseColumnName=DEPTNO;BaseSchemaName=SCOTT;BaseTableName=DEPT;
               NativeDataType=number;ProviderType=Int32;ProviderDBType=Int32;
               DataType=System.Int32;ColumnSize=4;NumericPrecision=10;
               NumericScale=3;AllowDBNull=false;IsKey=true'" />

          <add name="SCOTT.&quot;GetEmpAndDept&quot;
               .RefCursorMetaData.DEPTS.Column.1"
               value="implicitRefCursor metadata='ColumnName=DNAME;
               BaseColumnName=DNAME;BaseSchemaName=SCOTT;BaseTableName=DEPT;
               NativeDataType=varchar2;ProviderType=Varchar2;
               ProviderDBType=String;DataType=System.String;
               ColumnSize=10;AllowDBNull=true'" />
          </settings>
      </oracle.dataaccess.client>
    </configuration>

構成ファイルを使用するアプリケーションのサンプル

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

    class Program
    {
      static void Main(string[] args)
      {
        try
        {
          // Open a connection
          string constr =
            "User Id=scott;Password=tiger;Data Source=inst1";
          OracleConnection con = new OracleConnection(constr);
          con.Open();

          // Use implicit REF CURSOR binding
          //   to execute SCOTT.GETEMP function
          // Use bind by position as configured
          //   in app.config for SCOT.GETEMP
          OracleCommand cmd = con.CreateCommand();
          cmd.CommandText = "SCOTT.GETEMP";
          cmd.CommandType = CommandType.StoredProcedure;
          cmd.BindByName = false;
          OracleParameter empid = cmd.Parameters.Add("empid",
            OracleDbType.Int32, ParameterDirection.Input);
          empid.Value = 7654;

          // Populate the DataSet
          OracleDataAdapter adapter = new OracleDataAdapter(cmd);
          DataSet ds = new DataSet();
          adapter.Fill(ds);
          Console.WriteLine("Retrieved {0} row from EMP",
            ds.Tables[0].Rows.Count);

          // Use implicit REF CURSOR binding
          //   to execute "SCOTT"."GetEmpAndDept" procedure
          // Use bind by name as configured
          //   in app.config for "SCOTT"."GetEmpAndDept"
          cmd = con.CreateCommand();
          cmd.CommandText = "\"SCOTT\".\"GetEmpAndDept\"";
          cmd.CommandType = CommandType.StoredProcedure;
          cmd.BindByName = true;
          adapter = new OracleDataAdapter(cmd);
          adapter.Fill(ds);
          Console.WriteLine("Retrieved {0} rows from DEPT",
            ds.Tables[1].Rows.Count);
        }
        catch (Exception ex)
        {
          // Output the message
          Console.WriteLine(ex.Message);
          if (ex.InnerException != null)
          {
            // If any details are available regarding
            // errors in the app.config, print them out
            Console.WriteLine(ex.InnerException.Message);
            if (ex.InnerException.InnerException != null)
            {
              Console.WriteLine(
                ex.InnerException.InnerException.Message);
            }
          }
        }
      }
    }

## 使用上の考慮事項

この項では、暗黙的な`REF CURSOR`の使用に関する次の考慮事項について説明します。

- CommandTextプロパティに関する考慮事項

- バインドに関する考慮事項

- オーバーロードされたストアド・プロシージャ

- タイプの初期化時の例外

- 関数インポートでのストアド・ファンクションの使用

### CommandTextプロパティに関する考慮事項

ODP.NETアプリケーションでは、ストアド・プロシージャ名と`OracleCommand CommandText`が完全に一致している必要があります。データベースのストアド・プロシージャ名が`SCOTT.TESTPROC`であると仮定します。この場合に`CommandText`に`TESTPROC`を使用すると、ODP.NETによって、`TESTPROC`に一致するエントリのみが検索されます。`TESTPROC`に現行のスキーマ名が自動的に追加されません。このため、ここでは適切な`CommandText`として、`SCOTT.TESTPROC`を使用する必要があります。

また、`CommandText`では大/小文字が区別されるため、データベースのストアド・プロシージャ名と同じ大/小文字を使用する必要があります。このため、データベースのストアド・プロシージャ名が`SCOTT.Testproc`である場合は、`CommandText`に`SCOTT.Testproc`を使用する必要があります。

### バインドに関する考慮事項

`REF CURSOR`パラメータに関する情報が構成ファイルに追加された場合、アプリケーションで、`OracleCommand`に`REF CURSOR`パラメータを明示的にバインドしないようにします。ODP.NETでは、構成ファイルで指定された情報に基づいて、`REF CURSOR`パラメータが適切な位置に自動的にバインドされます。アプリケーションのストアド・プロシージャに`REF CURSOR`以外のバラメータも存在する場合、これらのパラメータについては、引き続き明示的に`OracleCommand`にバインドする必要があります。

ストアド・プロシージャの構成ファイルで指定されている情報で、`REF CURSOR`パラメータが名前で識別されている場合は、`REF CURSOR`以外のすべてのパラメータも名前でバインドする必要があります。また、この場合は、`OracleCommand`オブジェクトの`BindByName`プロパティを`true`に設定する必要があります。Entity Frameworkでは、ストアド・プロシージャの実行に常にBindByNameが使用されます。.NET構成ファイルのパラメータ名には、データベースでストアド・プロシージャを作成する際に使用したものと同じ大/小文字を使用する必要があります。

`OracleCommand` `BindByName`プロパティが`false`に設定されている場合(デフォルト)、ODP.NETでは、パラメータが位置に基づいてバインドされ、かつすべてのパラメータが適切な順序で指定されていると想定されます。この場合、構成ファイルで指定されているパラメータは、構成ファイルに表示される順序と同じ順序でバインドされます。

### オーバーロードされたストアド・プロシージャ

ODP.NETでは、構成ファイル内に、同じ名前のストアド・プロシージャが複数存在することはできません。オーバーロードされたストアド・プロシージャを使用すると、ODP.NETアプリケーションの構成ファイルには、オーバーロードされた1つのストアド・プロシージャの情報のみが格納されます。

### タイプの初期化時の例外

タイプの初期化時の例外は、.NET構成ファイルに無効なエントリがある場合に発生することがあります。捕捉した例外と内部例外を評価して、例外を発生させている.NET構成ファイル・エントリまたは属性設定を確認します。

ODP.NETトレースは、ODP.NETによって解析された.NET構成ファイル・エントリのうち、有効なエントリおよび無効なエントリを記録します。.NET構成ファイルに関連するエントリを検索するには、`TraceLevel`を開始、終了およびSQL文の情報レベルに設定します。エラーが発生している場合、暗黙的な`REF CURSOR`のバインドに関連するトレース・エントリには、`(REFCURSOR)`エントリとともに`(ERROR)`が表示されます。

### 関数インポートでのストアド・ファンクションの使用

関数インポートでは、ストアド・プロシージャのみがサポートされ、ストアド・ファンクションはサポートされません。ストアド・ファンクションが.NET構成ファイルで適切に構成されている場合であっても、作成したAdd Function Import ダイアログをEntity Data Modelで使用する際に、ストアド・ファンクションによって返される`REF CURSOR`のメタデータ情報がGet Column Informationボタンによって返されません。