Potrzebuję pomocy w zrozumieniu, jeśli sposób, w jaki próbuję użyć Ref Cursor jako parametru ReturnValue dla wielu rekordów/wartości, przy czym PL/SQL jest właśnie tekstem CommandText obiektu OracleCommand, a nie w zapisanej procedurze lub funkcji, jest nawet możliwe.Jak używać Oracle Ref Cursor z C# ODP.NET jako parametru ReturnValue, bez użycia zapisanej funkcji lub procedury?
Jeśli nie jest to możliwe, staram się znaleźć sposób na wydanie instrukcji PL/SQL, która zaktualizuje nieznaną liczbę rekordów (w zależności od tego, ile z nich zgadza się z klauzulą WHERE) i zwraca Identyfikatory wszystkich rekordów Zaktualizowane w OracleDataReader, przy użyciu pojedynczego obiegu do bazy danych, bez użycia procedury składowanej lub funkcji.
Pracuję z Oracle 11g przy użyciu ODP.NET do komunikacji z istniejącą bazą kodową C# .NET 4.0, która używa połączenia SQL do pobierania/modyfikowania danych. Uproszczona definicja tabeli testu używam wygląda tak:
CREATE TABLE WorkerStatus
(
Id NUMERIC(38) NOT NULL
,StateId NUMERIC(38) NOT NULL
,StateReasonId NUMERIC(38) NOT NULL
,CONSTRAINT PK_WorkerStatus PRIMARY KEY (Id)
)
ja wstępnie wypełnić tabelę z trzech wartości testowych tak:
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (1, 0, 0)';
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (2, 0, 0)';
EXECUTE IMMEDIATE 'INSERT INTO WorkerStatus (Id, StateId, StateReasonId)
VALUES (3, 0, 0)';
END;
Istniejąca instrukcja SQL, ładowane z pliku skryptu nazwany Oracle_UpdateWorkerStatus2, a zawarte w OracleCommand.CommandText wygląda tak:
DECLARE
TYPE id_array IS TABLE OF WorkerStatus.Id%TYPE INDEX BY PLS_INTEGER;
t_ids id_array;
BEGIN
UPDATE WorkerStatus
SET
StateId = :StateId
,StateReasonId = :StateReasonId
WHERE
StateId = :CurrentStateId
RETURNING Id BULK COLLECT INTO t_Ids;
SELECT Id FROM t_Ids;
END;
stworzyłem mały program w C# test próbować izolować, gdzie jestem coraz o RA-01036 „nielegalne zmiennej Nazwa/numer” błąd, który ma główny korpus, który wygląda tak:
using System;
using System.Configuration;
using System.Data;
using System.Text;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
namespace OracleDbTest
{
class Program
{
static void Main(string[] args)
{
// Load the SQL command from the script file.
StringBuilder sql = new StringBuilder();
sql.Append(Properties.Resources.Oracle_UpdateWorkerStatus2);
// Build and excute the command.
OracleConnection cn = new OracleConnection(ConfigurationManager.ConnectionStrings["OracleSystemConnection"].ConnectionString);
using (OracleCommand cmd = new OracleCommand(sql.ToString(), cn))
{
cmd.BindByName = true;
cn.Open();
OracleParameter UpdatedRecords = new OracleParameter();
UpdatedRecords.OracleDbType = OracleDbType.RefCursor;
UpdatedRecords.Direction = ParameterDirection.ReturnValue;
UpdatedRecords.ParameterName = "rcursor";
OracleParameter StateId = new OracleParameter();
StateId.OracleDbType = OracleDbType.Int32;
StateId.Value = 1;
StateId.ParameterName = "StateId";
OracleParameter StateReasonId = new OracleParameter();
StateReasonId.OracleDbType = OracleDbType.Int32;
StateReasonId.Value = 1;
StateReasonId.ParameterName = "StateReasonId";
OracleParameter CurrentStateId = new OracleParameter();
CurrentStateId.OracleDbType = OracleDbType.Int32;
CurrentStateId.Value = 0;
CurrentStateId.ParameterName = "CurrentStateId";
cmd.Parameters.Add(UpdatedRecords);
cmd.Parameters.Add(StateId);
cmd.Parameters.Add(StateReasonId);
cmd.Parameters.Add(CurrentStateId);
try
{
cmd.ExecuteNonQuery();
OracleDataReader dr = ((OracleRefCursor)UpdatedRecords.Value).GetDataReader();
while (dr.Read())
{
Console.WriteLine("{0} affected.", dr.GetValue(0));
}
dr.Close();
}
catch (OracleException e)
{
foreach (OracleError err in e.Errors)
{
Console.WriteLine("Message:\n{0}\nSource:\n{1}\n", err.Message, err.Source);
System.Diagnostics.Debug.WriteLine("Message:\n{0}\nSource:\n{1}\n", err.Message, err.Source);
}
}
cn.Close();
}
Console.WriteLine("Press Any Key To Exit.\n");
Console.ReadKey(false);
}
}
}
próbowałam zmianę nazwy parametrów, nazywania i nie nazewnictwa parametr UpdatedRecords, zmieniając kolejność tak Zaktualizowane zapisy są pierwsze lub ostatnie. Najbliższą rzeczą, którą znalazłem do tej pory jest następujące pytanie StackOverflow (How to call an Oracle function with a Ref Cursor as Out-parameter from C#?), ale nadal używa funkcji przechowywanej, o ile mogę powiedzieć.
Uruchamianie skryptu/SQL Oracle_UpdateWorkerStatus2 PL z SQL Developer, to otwiera okno „Enter wiąże” gdzie mogę wprowadzić wartości CurentStateId, StateId i StateReasonId jak w powyższym kodzie, ale daje następujący raport o błędzie:
Error report:
ORA-06550: line 13, column 17:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 13, column 2:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Nie do końca rozumiem, dlaczego mówi mi, że tabela nie istnieje, kiedy zdefiniowałem tabelę WorkerStatus i zadeklarowałem zmienną t_Ids, typu id_array, również na tabelę. Każda pomoc tutaj jest bardzo doceniana.
Czy może to być problem z uprawnieniami/widocznością? Po ręcznym połączeniu się z kontem Oracle, na którym wykonywałeś skrypt "Oracle_UpdateWorkerStatus2", możesz wybrać z tabeli status_umenu? –
Jestem w stanie wybrać z tabeli WorkerStatus, a także upuścić i utworzyć go. Jestem całkiem nowy w firmie Oracle, więc nie wiem, czy są jakieś specjalne przywileje, których potrzebowałbym, aby móc korzystać z kursorów ref., Ale nasz technik IT/DBA ustawił mnie z wszystkimi przywilejami zwykle używanymi przez naszych programistów, więc nie uważam, że jest to kwestia uprzywilejowana. Poproszę go jednak w poniedziałek. – Paul
Sprawdzone z naszym DBA, i nie jest on świadomy żadnych specjalnych uprawnień wymaganych do robienia tego, co próbuję. Zrobił też szybki skan tego, co mam tutaj, i nie widzi żadnego powodu, dla którego nie działa. Jakieś przemyślenia na temat tego, co robię źle, lub inny sposób osiągnięcia celów? – Paul