我正在使用Entity Framework 6和ODP.NET,并将存储过程导入到应用程序的数据模型中。 ODP.NET无法自动导入使用In / Out游标的存储过程,并且需要手动将其信息添加到app.config中。更糟糕的是,我有三十多个导入程序,其中大部分都使用In / Out游标。我已经看到generate config information automatically有可能,但这似乎只适用于直接返回游标的函数。 (也许还有Out游标?)
是否有一种自动方法可以检索存储过程游标返回的列名和数据类型,而无需手动手动运行所有信息?
我当前如何在app.config中导入过程的一个示例,为公共消费进行了清理:
<storedProcedure schema="SCHEMA" name="PACKAGE.PROCEDURENAME">
<refCursor name="ioCursor">
<bindInfo mode="InputOutput"/>
<metadata columnOrdinal="0" columnName="SOMEID" providerType="Int32" allowDBNull="false" nativeDataType="Number"/>
<metadata columnOrdinal="1" columnName="SOMEOTHERID" providerType="Int32" allowDBNull="false" nativeDataType="Number"/>
<metadata columnOrdinal="2" columnName="SOMESTRING" providerType="Varchar2" allowDBNull="false" nativeDataType="Varchar2"/>
</refCursor>
</storedProcedure>
如何在程序包中出现相同的程序:
PROCEDURE PROCEDURENAME (
someInputId IN schema.table.column%TYPE
,ioCursor IN OUT t_ref_cur
)
IS
BEGIN
vProcedureName := 'PROCEDURENAME';
OPEN ioCursor FOR SELECT a.some_id SOMEID
,a.some_other_id SOMEOTHERID
,b.some_string SOMESTRING
FROM schema.table_a a,
schema.table_b b
WHERE (selection criteria removed for brevity's sake)
END
正如您所看到的,为了正确填写app.config中的元数据,我需要运行SOMEID,SOMEOTHERID和SOMESTRING的名称和类型,这三者都可能位于不同的表中。自动提取这些数据的一些方法很可爱。
〜EDIT〜:
感谢Christian Shay在下面的回答,我最终提出了一些代码,我能够构建一个工具。它与ODP.NET在Server Explorer中的“Run Stored Procedure”完全相同,但它也适用于InOut Ref Cursors!下面有一些伪代码,以显示我最终做的基本想法。
using(ContextItem context = new ContextItem())
{
OracleCommand cmd = context.Database.Connection.CreateCommand() as OracleCommand;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "PROCEDURE_NAME_HERE";
//do the following for all of the input parameters for the stored proc
OracleDbType paramType = OracleDbType.SomeType;
OracleParameter param = new OracleParameter("parameterName", paramType);
param.Value = someValue;
//or, for cursors
OracleDbType cursorType = OracleDbType.RefCursor;
ParameterDirection direction = ParameterDirection.SomeCursorDirection;
OracleParameter cursorParam = new OracleParameter("cursorName", OracleDbType.RefCursor, direction);
cmd.Parameters.Add(param);
cmd.Parameters.Add(cursorParam);
if (db.Database.Connection.State != ConnectionState.Open)
{
db.Database.Connection.Open();
}
var reader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
var table = reader.GetSchemaTable();
for(int i = 0; i < reader.FieldCount; i++)
{
/*Now you have access to everything you need for an EF config:
Ordinals, column names, provider types, not-null-ness, and native data types*/
}
}
答案 0 :(得分:1)
您可以选择这样的元数据:
SELECT *
FROM ALL_ARGUMENTS
WHERE OWNER = '<your schema name>'
and object_name = '<your procedure name>'
示例输出:
答案 1 :(得分:1)
下面是一些示例代码,展示了如何在不将代码导入模型的情况下从EF代码调用procs - 实际上是在拉出OracleCommand对象:
var ctx = new TestContext();
var cmd = ctx.Database.Connection.CreateCommand() as OracleCommand;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "SOMESTOREDPROC";
var p_rc1 = new OracleParameter("p_rc1", OracleDbType.RefCursor, ParameterDirection.Output);
var p_rc2 = new OracleParameter("p_rc2", OracleDbType.RefCursor, ParameterDirection.Output);
cmd.Parameters.Add(p_rc1);
cmd.Parameters.Add(p_rc2);
if (ctx.Database.Connection.State != ConnectionState.Open)
ctx.Database.Connection.Open();
var reader = cmd.ExecuteReader();
答案 2 :(得分:0)
您无需手动添加元数据。查看Oracle Developer Tools for Visual Studio联机帮助中的实体框架章节。使用“运行存储过程”对话框执行此操作。它会自动将元数据添加到配置文件中。
请参阅那里的函数导入部分。
注意:“导入功能”对话框仅使用存储过程中的第一个REF CURSOR。它按惯例成为导入的实体函数的返回值。如果你有多个REF CURSOR,你可能需要用另一个SP包装这些SP。
此外,在您的代码中,您没有使用REF CURSOR。您正在使用“t_ref_cur”。那是什么?如果它是用户定义的类型,这将不起作用,您将需要至少包装它以返回实际的REF CURSOR,因为在这种情况下不支持用户定义类型(并且上面提到的运行过程对话框也不喜欢它)