2012-04-18 32 views
8

This answer to this question là tốt, nhưng tôi đang tìm mã ADO.NET để có thể gửi một mảng hoặc bảng đến một thủ tục Oracle và sau đó sử dụng bảng đó trong thủ tục.Làm thế nào để sử dụng tham số Array/Table với Oracle (ODP.NET 10g) thông qua ADO.NET/C#?

Trong SQL Server các thông số bảng có giá trị, nó khá đơn giản:

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 

Sau đó trên máy khách:

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

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

Đây là những gì tôi hiện có:

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); 

Và Tôi nhận được thông tin này trên 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

Xin xem http://stackoverflow.com/questions/5557318/can-an-oracle-stored-procedure-that-has-a-nested-table-parameter-be-called-từ – Eggi

+0

@Eggi Thật không may là kỹ thuật không hoạt động với 10g clie nt và cố gắng kết hợp 11g client và 10g client trong .NET (hoặc thậm chí để làm cho chúng chạy trên client 11g) là cho tôi phù hợp với lỗi nhà cung cấp không tương thích và các vấn đề intialization constructor. –

Trả lời

18

này làm việc cho ODP.NET (odac):

gói Oracle của bạn sẽ được thiết lập như:

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; 

Sau đó, mã # C của bạn sẽ trông như thế:

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

Cảm ơn - Tôi đang thử phương pháp này thay vì phương pháp UDT chỉ hoạt động với máy khách 11g đang phát triển. Tuy nhiên, tôi đang nhận được System.AccessViolationException –

+0

wow, bạn có đang sử dụng mã không được quản lý không? – tbone

+0

không, không có mã được quản lý –

Các vấn đề liên quan