2012-04-18 2 views
8

This answer zu this question ist in Ordnung, aber ich suche nach ADO.NET-Code in der Lage sein, ein Array oder eine Tabelle zu einer Oracle-Prozedur zu senden und dann diese Tabelle in der Prozedur verwenden.Wie verwende ich Array/Table Parameter zu Oracle (ODP.NET 10g) über ADO.NET/C#?

In SQL Server-Tabellenwertparameter, es ist ziemlich einfach:

CREATE TYPE [dbo].[IntTable] AS TABLE(
    [intvalue] [int] NOT NULL, 
    PRIMARY KEY CLUSTERED 
    (
     [intvalue] ASC 
    )WITH (IGNORE_DUP_KEY = OFF) 
) 
GO 

CREATE PROCEDURE dbo.UseTable 
    @SomeInt INT 
    ,@IntTable dbo.IntTable READONLY 
AS 
BEGIN 
    -- Do whatever using @SomeInt and @IntTable like: 
    INSERT INTO Assignments (masterid, childid) 
    SELECT @SomeInt, intvalue 
    FROM @IntTable 
END 
GO 

Dann auf dem Client:

var param = new List<int>(); 
param.Add(1); 
param.Add(2); 

Cm.Parameters 
    .AddWithValue("@IntTable", param /* IEnumerable<Int> */) 
    .SqlDbType = SqlDbType.Structured 

Dies ist, was ich derzeit haben:

CREATE OR REPLACE TYPE TRAIT_ID_TABLE AS TABLE OF NUMBER; 

PROCEDURE SET_TRAITS(P_CUST_TANK_PROD_ID IN CUST_TANK_PROD.CUST_TANK_PROD_ID%TYPE, P_TRAIT_IDS IN TRAIT_ID_TABLE) 
AS 
BEGIN 
    DELETE FROM TANK_TRAIT 
     WHERE CUST_TANK_PROD_ID = P_CUST_TANK_PROD_ID; 

    INSERT INTO TANK_TRAIT(CUST_TANK_PROD_ID, TRAIT_ID) 
    SELECT P_CUST_TANK_PROD_ID, COLUMN_VALUE FROM TABLE(P_TRAIT_IDS); 

    COMMIT; 
EXCEPTION 
    WHEN OTHERS 
    THEN 
    ROLLBACK; 
END; 


var param = new OracleParameter(); 
param.ParameterName = "P_TRAIT_IDS"; 
param.OracleDbType = OracleDbType.Decimal; 
param.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 
param.Direction = ParameterDirection.Input; 
param.Value = traitIdList.ToArray<int>(); 
param.Size = traitIdList.Count; 
cmd.Parameters.Add(param); 

Und Ich bekomme dies auf der ExecuteNonQuery:

System.AccessViolationException was caught 
    Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 
    Source=Oracle.DataAccess 
    StackTrace: 
     at Oracle.DataAccess.Client.OpsSql.ExecuteNonQuery(IntPtr opsConCtx, IntPtr& opsErrCtx, IntPtr& opsSqlCtx, IntPtr& opsDacCtx, IntPtr opsSubscrCtx, Int32& isSubscrRegistered, OpoSqlValCtx*& pOpoSqlValCtx, OpoSqlRefCtx& pOpoSqlRefCtx, IntPtr[] pOpoPrmValCtx, OpoPrmRefCtx[] pOpoPrmRefCtx, OpoMetValCtx*& pOpoMetValCtx, Int32 prmCnt) 
     at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery() 
     at EDC2.Domain.TraitList.SaveTraits(String connectionString) in C:\code\EDC2\trunk\app\EDC2.Domain\Trait.cs:line 195 
    InnerException: 
+1

Bitte sehen:

CREATE OR REPLACE package SOME_PACKAGE as ... type t_number_tab is table of number index by pls_integer; ... procedure ins_test(i_id_tab in t_number_tab, o_inserted out number); end SOME_PACKAGE; CREATE OR REPLACE package body SOME_PACKAGE as procedure ins_test(i_id_tab in t_number_tab, o_inserted out number) is begin -- inserts all records to test table based on incoming table of ids forall i in i_id_tab.first .. i_id_tab.last insert into TEST_TAB (id, val1, val2) select id,val1,val2 from main_tab where id = i_id_tab(i); o_inserted := SQL%ROWCOUNT; commit; exception when others then rollback; raise; end ins_test; ... end SOME_PACKAGE; 

Dann Code C# aussehen würde, http://stackoverflow.com/questions/5557318/can-an-oracle-stored-procedure-that-has-a-nested-table-parameter-be-called-from – Eggi

+0

@Eggi Leider arbeitet diese Technik nicht mit der 10g klies nt und der Versuch, 11g Client und 10g Client in .NET zu mischen (oder sogar zu versuchen, alle auf dem 11g Client zu laufen), gibt mir Anfälle mit inkompatiblen Anbieterfehlern und Konstruktorinitialisierungsproblemen. –

Antwort

18

Dies funktioniert für ODP.NET (ODAC):

Sie wird Oracle-Paket wie sein Setup:

string connStr = "User Id=xxx;Password=xxxx;Data Source=xxxxx;"; 
OracleConnection _conn = new OracleConnection(connStr); 
_conn.Open(); 

OracleCommand cmd = _conn.CreateCommand(); 
cmd.CommandText = "some_package.ins_test"; 
cmd.CommandType = CommandType.StoredProcedure; 

OracleParameter p1 = new OracleParameter(); 
OracleParameter p2 = new OracleParameter(); 

p1.OracleDbType = OracleDbType.Decimal; 
p1.Direction = ParameterDirection.Input; 
p2.OracleDbType = OracleDbType.Decimal; 
p2.Direction = ParameterDirection.Output; 

p1.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 
p1.Value = new int[3] { 1, 2, 3 }; 
p1.Size = 3; 

cmd.Parameters.Add(p1); 
cmd.Parameters.Add(p2); 

cmd.ExecuteNonQuery(); 
+0

Danke - ich versuche dies anstelle der UDT-Methode, die nur mit 11g Client in Entwicklung funktioniert. Ich bekomme jedoch System.AccessViolationException –

+0

wow, verwenden Sie nicht verwalteten Code? – tbone

+0

Nein, kein gemanagter Code –

Verwandte Themen