3.12 暗黙的な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構成ファイルでバインド情報のみを定義する必要があります。
この項には次のトピックが含まれます:
3.12.1 .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
属性内で二重引用符を使用する必要がある場合は、"
を使用します。たとえば、データベースのスキーマ名がHrSchema
、パッケージ名がHrPackage
、ストアド・プロシージャ名がHrStoredProcedure
である場合、構成ファイルには次を使用する必要があります。
<add name=""HrSchema"."HrPackage"."HrStoredProcedure".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で必須/オプション | 説明 |
---|---|---|---|
|
|
必須 |
列の名前です。 |
|
|
必須 |
列のデータベース列タイプ( |
|
|
必須 |
Oracleタイプ。たとえば、 |
|
|
オプション |
列に別名が使用されている場合の、データベース内の列名。 |
|
|
オプション |
列を含むデータベース内のスキーマ名。 |
|
|
オプション |
列を含むデータベース内の表名またはビュー名。 |
|
|
オプション |
列内の値として可能な最大長 |
|
|
オプション |
列が数値のデータ型の場合の、列の最大精度。 |
|
|
オプション |
列が数値のデータ型の場合の、列の最大スケール。 |
|
|
オプション |
列値が一意かどうかを示します。 |
|
|
オプション |
列がキー列かどうかを示します。 |
|
|
オプション |
列が |
|
|
オプション |
共通言語のランタイム型にマップします。 |
|
|
オプション |
null値が許可されている場合は |
|
|
オプション |
列が別名の場合は |
|
|
オプション |
|
|
|
オプション |
列が式の場合は |
|
|
オプション |
列が非表示の場合は |
|
|
オプション |
列が読取り専用の場合は |
|
|
オプション |
|
|
|
オプション |
UDTのタイプ名。 |
|
|
オプション |
|
|
|
オプション |
オブジェクトの名前を表します。 |
表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'" />
3.12.2 構成ファイルおよびアプリケーションのサンプル
この項では、サンプル・アプリケーションを構築して、暗黙的な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."GetEmpAndDept".RefCursor.EMPS" value="implicitRefCursor bindinfo='mode=Output'" /> <!-- The following is for SCOTT.GETEMP's EMPS REF CURSOR metadata --> <add name="SCOTT."GetEmpAndDept" .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."GetEmpAndDept" .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."GetEmpAndDept".RefCursor.DEPTS" value="implicitRefCursor bindinfo='mode=Output'" /> <add name="SCOTT."GetEmpAndDept" .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."GetEmpAndDept" .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); } } } } }
3.12.3 使用上の考慮事項
この項では、暗黙的なREF CURSOR
の使用に関する次の考慮事項について説明します。
3.12.3.1 CommandTextプロパティに関する考慮事項
ODP.NETアプリケーションでは、ストアド・プロシージャ名とOracleCommand CommandText
が完全に一致している必要があります。データベースのストアド・プロシージャ名がSCOTT.TESTPROC
であると仮定します。この場合にCommandText
にTESTPROC
を使用すると、ODP.NETによって、TESTPROC
に一致するエントリのみが検索されます。TESTPROC
に現行のスキーマ名が自動的に追加されません。このため、ここでは適切なCommandText
として、SCOTT.TESTPROC
を使用する必要があります。
また、CommandText
では大/小文字が区別されるため、データベースのストアド・プロシージャ名と同じ大/小文字を使用する必要があります。このため、データベースのストアド・プロシージャ名がSCOTT.Testproc
である場合は、CommandText
にSCOTT.Testproc
を使用する必要があります。
3.12.3.2 バインドに関する考慮事項
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では、パラメータが位置に基づいてバインドされ、かつすべてのパラメータが適切な順序で指定されていると想定されます。この場合、構成ファイルで指定されているパラメータは、構成ファイルに表示される順序と同じ順序でバインドされます。
3.12.3.3 オーバーロードされたストアド・プロシージャ
ODP.NETでは、構成ファイル内に、同じ名前のストアド・プロシージャが複数存在することはできません。オーバーロードされたストアド・プロシージャを使用すると、ODP.NETアプリケーションの構成ファイルには、オーバーロードされた1つのストアド・プロシージャの情報のみが格納されます。
3.12.3.4 タイプの初期化時の例外
タイプの初期化時の例外は、.NET構成ファイルに無効なエントリがある場合に発生することがあります。捕捉した例外と内部例外を評価して、例外を発生させている.NET構成ファイル・エントリまたは属性設定を確認します。
ODP.NETトレースは、ODP.NETによって解析された.NET構成ファイル・エントリのうち、有効なエントリおよび無効なエントリを記録します。.NET構成ファイルに関連するエントリを検索するには、TraceLevel
を開始、終了およびSQL文の情報レベルに設定します。エラーが発生している場合、暗黙的なREF CURSOR
のバインドに関連するトレース・エントリには、(REFCURSOR)
エントリとともに(ERROR)
が表示されます。