Что я делаю неправильно, пытаясь использовать этот пакет / процедуру оракула? - PullRequest
1 голос
/ 21 января 2011

Я написал этот пакет

CREATE OR REPLACE 
PACKAGE CURVES AS 
  type t_forecast_values is table of test.column2%TYPE index by varchar(20);
  assoc_array t_forecast_values;
  procedure sp_insert (param1 in varchar2, param2 in number);
END CURVES;

create or replace
package body curves as
  procedure sp_insert (param1 in varchar2, param2 in number) as
  begin
    assoc_array(param1) := param2;
    DECLARE primarykey NUMBER(10);
    BEGIN
      FOR i IN 1..2
      LOOP
        SELECT seq_curves.nextval INTO primarykey FROM dual;
        INSERT INTO TEST (column1, column2, column3)
        VALUES (primarykey, param1, assoc_array(param1));

        INSERT INTO TEST2 (column1, column2)
        VALUES (primarykey, 'default');
      END LOOP ;
    END;
  end sp_insert;
end curves;

Я вызываю процедуру через этот код c #:

class Program
    {
        private static string connString = @"User Id=User; Password=root; Data Source=SOURCE";

        private static List<string> forecast_types = new List<string> { "a", "b" };
        private static List<double> forecast_values = new List<double> { .1, .2 };

        static void Main(string[] args)
        {
            using (var con = new OracleConnection(connString))
            {
                string query = "BEGIN curves.sp_insert(:forecast_types, :forecast_values); END;";

                try
                {
                    con.Open();

                    using (OracleCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = query;
                        cmd.CommandType = CommandType.Text;
                        cmd.BindByName = true;

                        cmd.Parameters.Add(new OracleParameter
                            {
                                ParameterName = ":forecast_types",
                                OracleDbType = OracleDbType.Varchar2,
                                Value = forecast_types.ToArray(),
                                Direction = ParameterDirection.Input,
                                CollectionType = OracleCollectionType.PLSQLAssociativeArray
                            }
                        );
                        cmd.Parameters.Add(new OracleParameter
                        {
                            ParameterName = ":forecast_values",
                            OracleDbType = OracleDbType.Double,
                            Value = forecast_values.ToArray(),
                            Direction = ParameterDirection.Input,
                            CollectionType = OracleCollectionType.PLSQLAssociativeArray
                        }
                        );

                        cmd.ExecuteNonQuery();
                    }
                }
                catch (System.Exception ex)
                {
                    System.Console.WriteLine(ex);
                }
                finally
                {
                    con.Close();
                }
            }
        }
    }

Я получаю следующую ошибку:

Oracle.DataAccess.Client.OracleException ORA-06550: line 1, column 7: 
PLS-00306: wrong number or types of arguments in call to 'SP_INSERT'
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'SP_INSERT'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored at     Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck)
   at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, String procedure, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, Boolean bCheck)
   at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()
   at OracleTest.Program.Main(String[] args) in \\comp\user$\Visual Studio 2010\Projects\OracleTest\OracleTest\Program.cs:line 57

Я понятия не имею, чтобы решить проблему, пока.Любая помощь приветствуется.

Ответы [ 2 ]

4 голосов
/ 21 января 2011

Ваш пакет принимает не ассоциативный массив PLSQL, а отдельные элементы.Я полагаю, что вы пытаетесь сделать вставку массива (которая в значительной степени упаковывает в C # ваш код X раз и массово отправляет его в базу данных для выполнения работы)

эта ссылка напрямую описываетчто вы хотите сделать: http://www.oracle.com/technology/sample_code/tech/windows/odpnet/howto/arraybind/index.html

(я сделал несколько изменений в вашем коде, а именно:

  1. удалил ассоциированный массив pl / sql тип элемента
  2. добавлен ArrayBindCount
  3. Вы использовали анонимный блок, заменили его на вызов хранимой процедуры

1 & 2 должны решить вашу проблему, в то время как # 3 - больше синтаксического сахара

однако, этот код не проверен, но работает

class Program
    {
        private static string connString = @"User Id=User; Password=root; Data Source=SOURCE";

        private static List<string> forecast_types = new List<string> { "a", "b" };
        private static List<double> forecast_values = new List<double> { .1, .2 };

        static void Main(string[] args)
        {
            using (var con = new OracleConnection(connString))
            {
                //string query = "BEGIN curves.sp_insert(:forecast_types, :forecast_values); END;";
                string query = "curves.sp_insert";

                try
                {
                    con.Open();

                    using (OracleCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = query;
                        cmd.CommandType = CommandType.StoredProcedure; // CommandType.Text; //you can change this to a stored procedure and not utilize the anonymous block

                        cmd.ArrayBindCount = 2; //use ArrayBindCount

                        cmd.BindByName = true;

                     cmd.Parameters.Add(new OracleParameter
                        {
                            ParameterName = ":forecast_types",
                            OracleDbType = OracleDbType.Varchar2,
                            Value = forecast_types.ToArray(),
                            Direction = ParameterDirection.Input,
                            //CollectionType = OracleCollectionType.PLSQLAssociativeArray //this is not needed
                        }
                    );
                    cmd.Parameters.Add(new OracleParameter
                    {
                        ParameterName = ":forecast_values",
                        OracleDbType = OracleDbType.Double,
                        Value = forecast_values.ToArray(),
                        Direction = ParameterDirection.Input,
                        //CollectionType = OracleCollectionType.PLSQLAssociativeArray  //this is not needed
                    }
                        );

                        cmd.ExecuteNonQuery();
                    }
                }
                catch (System.Exception ex)
                {
                    System.Console.WriteLine(ex);
                }
                finally
                {
                    con.Close();
                }
            }
        }
    }

РЕДАКТИРОВАТЬ


Я заметил, что вы сделали попробуйте передать ассоциативный массив (я вижу создание типа зацикливания в процедуре).

Это тоже не сложно сделать. На этом замечании вы на правильномtrack.

вам нужно изменить пакет, чтобы в него передавались массивы.через параметры CREATE ИЛИ ЗАМЕНИТЬ ПАКЕТНЫЕ ИЗОБРАЖЕНИЯ КАК тип t_forecast_values ​​является таблицей test.column2% TYPE index by varchar (20);assoc_array t_forecast_values;

  --need to create an assoc.array for numbers
  type t_numbera_values is table of test.column2%TYPE index by number(10);

  --changed to accept the assoc.array to varchar and numbers
  procedure sp_insert (param1 in t_forecast_values, param2 in t_numbera_values);
END CURVES;

create or replace
PACKAGE BODY CURVES AS
  --changed to accept the assoc.array to varchar and numbers
  PROCEDURE SP_INSERT (PARAM1 IN T_FORECAST_VALUES, PARAM2 IN T_NUMBERA_VALUES) AS
  BEGIN
    --assoc_array(param1) := param2; /*not sure what the intent of this was...*/
    DECLARE PRIMARYKEY NUMBER(10);
    BEGIN
      FOR i IN PARAM1.first .. PARAM1.last
      LOOP
        SELECT seq_curves.nextval INTO primarykey FROM dual;
        INSERT INTO TEST (COLUMN1, COLUMN2, COLUMN3)
        VALUES (primarykey, PARAM1(i), PARAM2(i));

        INSERT INTO TEST2 (column1, column2)
        VALUES (PRIMARYKEY, 'default');
      END LOOP ;
      --assuming you are going to add error handling here
    END;
  end sp_insert;
END CURVES;

, и вам нужно будет добавить параметр размера в список параметров как таковой

class Program
    {
        private static string connString = @"User Id=User; Password=root; Data Source=SOURCE";

        private static List<string> forecast_types = new List<string> { "a", "b" };
        private static List<double> forecast_values = new List<double> { .1, .2 };

        static void Main(string[] args)
        {
            using (var con = new OracleConnection(connString))
            {
                string query = "curves.sp_insert";

                try
                {
                    con.Open();

                    using (OracleCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = query;
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.BindByName = true;

                        cmd.Parameters.Add(new OracleParameter
                            {
                                ParameterName = "param1",
                                OracleDbType = OracleDbType.Varchar2,
                                Value = forecast_types.ToArray(),
                                Direction = ParameterDirection.Input,
                                CollectionType = OracleCollectionType.PLSQLAssociativeArray,
                                Size = 2
                            }
                        );
                        cmd.Parameters.Add(new OracleParameter
                        {
                            ParameterName = "param2",
                            OracleDbType = OracleDbType.Double,
                            Value = forecast_values.ToArray(),
                            Direction = ParameterDirection.Input,
                            CollectionType = OracleCollectionType.PLSQLAssociativeArray,
                            Size = 2                            
                        }
                        );

                        cmd.ExecuteNonQuery();
                    }
                }
                catch (System.Exception ex)
                {
                    System.Console.WriteLine(ex);
                }
                finally
                {
                    con.Close();
                }
            }
        }
    }

, чтобы получить отличный пример этого перехода к ORACLE_HOME \ odp.net \samples \ 2.x \ AssocArray \ AssocArray.cs он делает именно то, что вам нравится

весь приведенный выше код не протестирован, но должен вывести вас на правильный путь, либо из привязки массива (первый пример), либо путем передачи вмассив pl / sql (второй пример)

0 голосов
/ 21 января 2011

Не уверен, что это проблема, но я считаю, что OracleDbType.Double будет соответствовать типу базы данных FLOAT, а не NUMBER, который является объявленным типом второго параметра. Я думаю, вам следует установить тип второго параметра на OracleDbType.Decimal на в этой таблице .

...