ODP.NET 11gリリース2(11.2.0.3.0)以上では、.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構成ファイルでバインド情報のみを定義する必要があります。
この項の内容は次のとおりです。
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のバインドがサポートされていません。
|
metadataでは、AttributesListにパラメータのリストが含まれます。表3-16に、AttributesListに含むことのできるパラメータを示します。
例3-2に、bindinfoを使用するadd要素のサンプルを示します。ここで、スキーマ名はSCOTTで、ストアド・プロシージャ名はTESTPROCです。パラメータ名はparameter1です。モードはoutputです。
例3-3に、metadataを使用するadd要素のサンプルを示します。
例3-3 メタデータを含む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-16 属性リストで許可されるパラメータ
| 名前 | タイプ | Entity Frameworkで必須/オプション | 説明 |
|---|---|---|---|
|
|
|
必須 |
列の名前です。 |
|
|
|
必須 |
列のデータベース列タイプ( |
|
|
|
必須 |
Oracleタイプ。たとえば、 |
|
|
|
オプション |
列に別名が使用されている場合の、データベース内の列名。 |
|
|
|
オプション |
列を含むデータベース内のスキーマ名。 |
|
|
|
オプション |
列を含むデータベース内の表名またはビュー名。 |
|
|
|
オプション |
列内の値として可能な最大長 |
|
|
|
オプション |
列が数値のデータ型の場合の、列の最大精度。 |
|
|
|
オプション |
列が数値のデータ型の場合の、列の最大スケール。 |
|
|
|
オプション |
列値が一意かどうかを示します。 |
|
|
|
オプション |
列がキー列かどうかを示します。 |
|
|
|
オプション |
列が |
|
|
|
オプション |
共通言語のランタイム型にマップします。 |
|
|
|
オプション |
null値が許可されている場合は |
|
|
|
オプション |
列が別名の場合は |
|
|
|
オプション |
|
|
|
|
オプション |
列が式の場合は |
|
|
|
オプション |
列が非表示の場合は |
|
|
|
オプション |
列が読取り専用の場合は |
|
|
|
オプション |
|
|
|
|
オプション |
UDTのタイプ名。 |
|
|
|
オプション |
|
|
|
|
オプション |
オブジェクトの名前を表します。 |
表3-16にリストされている一部の属性については、結果セットのメタデータを使用して、値が自動的に設定されます。開発者は、明示的に値を設定して、デフォルトの値を上書きできます。
特定の操作でオプションとしてリストされている一部の属性について、明示的に定義する必要のある場合があります。たとえば、更新可能なREF CURSORでは、キー情報を定義する必要があります。
この項では、サンプル・アプリケーションを構築して、暗黙的な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);
}
}
}
}
}
この項では、暗黙的なREF CURSORの使用に関する次の考慮事項について説明します。
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ボタンによって返されません。