plsql: заменить 15-строчный запрос SELECT, вызываемый в C #? - PullRequest
0 голосов
/ 28 июня 2019

Мой фон sql server, поэтому, пожалуйста, потерпите меня.

У меня есть фрагмент кода на c #, который запускает 15-строчный запрос, который возвращает набор результатов.Вот как выглядит фрагмент:

public DataSet Oracle_LongComplexQuery()
{

    string oradb = "DATA SOURCE=OUR_SERVER:1521/XE;" +
        "PERSIST SECURITY INFO=True;USER ID=USER; password=PASS; Pooling=False;";

    string sql =
        "SELECT USERNAME, " +
        "USER_ID, " +
        "PASSWORD, " +
        "ACCOUNT_STATUS, " +
        "LOCK_DATE, " +
        "EXPIRY_DATE, " +
        "DEFAULT_TABLESPACE, " +
        "TEMPORARY_TABLESPACE, " +
        "CREATED, " +
        "PROFILE, " +
        "INITIAL_RSRC_CONSUMER_GROUP, " +
        "EXTERNAL_NAME, " +
        "PASSWORD_VERSIONS, " +
        "EDITIONS_ENABLED, " +
        "AUTHENTICATION_TYPE " +
        "from " +
        "dba_users";

    OracleConnection conn = new OracleConnection(oradb);
    conn.Open();
    OracleCommand cmd = conn.CreateCommand();
    cmd.CommandText = sql;
    cmd.CommandType = CommandType.Text;
    DataSet ds = new DataSet();
    OracleDataAdapter adapter = new OracleDataAdapter(cmd);
    try
    {
        adapter.Fill(ds);
    }
    catch (OracleException ex)
    {
        string er = ex.Message;
    }


    return ds;

}

Вместо вызова 15-строчного запроса, я хотел бы создать хранимую процедуру или функцию, которая будет делать то же самое Select без 15 строк.В tsql это была бы хранимая процедура, которую я бы назвал exec usp_getUsersInfo.

Поскольку я в основном работаю с tsql, я подумал, что хранимая процедура - это путь.Но это не так.Просто чтобы вернуть набор результатов, SP должен иметь параметр SYS_REFCURSOR для хранения данных и отдельный PRINT (по крайней мере, в SQL Developer) для просмотра курсора ссылки.

С функцией, которую я бы не хотелМне нужен оператор PRINT, но мне все еще нужен SYS_REFCURSOR, в котором хранятся данные.

Проблема с SYS_REFCURSOR заключается в том, что 1) весь набор результатов сохраняется в refcursor, аналогичнонабор данных, который затем отображается на экране (вместо немедленного отображения результатов).2) Несколько раз случалось, что я получал GC Overhead Limit Exceeded Error с большим количеством данных.

В любом случае, я не хочу создавать объект, которому нужен параметр только для просмотра набора результатов.Я просто хочу заменить 15-строчный оператор выбора одной строкой.

Любая помощь приветствуется.

1 Ответ

1 голос
/ 28 июня 2019

Мой опыт также связан с SQL Server, и мне пришлось побаловаться с Oracle, поэтому я чувствую вашу боль.У Oracle разные языковые контексты (я уверен, что есть лучший способ описать это), и не все может быть сделано в любом контексте, как в SQL Server.

Хорошая новость заключается в том, что хотя вы должнынапример, чтобы заставить его работать в SQL Developer, могут потребоваться операторы PRINT, реализация поставщика ADO.NET пакета Oracle.ManagedDataAccess довольно хороша для того, чтобы сделать SYS_REFCURSOR довольно простым в работе.

Начиная схранимая процедура, это довольно просто.Откройте выходной курсор CUR и дайте ему прочитать результаты нужного вам запроса.(Возможно, вы захотите / должны указать владельца и / или имя пакета с именем процедуры.)

CREATE OR REPLACE PROCEDURE MY_GET_USERS
(
    CUR OUT SYS_REFCURSOR
)
IS
BEGIN
    OPEN CUR FOR
    SELECT
        USERNAME,
        USER_ID,
        PASSWORD,
        ACCOUNT_STATUS,
        LOCK_DATE,
        EXPIRY_DATE,
        DEFAULT_TABLESPACE,
        TEMPORARY_TABLESPACE,
        CREATED,
        PROFILE,
        INITIAL_RSRC_CONSUMER_GROUP,
        EXTERNAL_NAME,
        PASSWORD_VERSIONS,
        EDITIONS_ENABLED,
        AUTHENTICATION_TYPE
    from
        dba_users;
END;

На стороне C # вам просто нужно добавить параметр RefCursor в OracleCommandобъект с указанным правильным типом параметра.

DataSet ds = new DataSet();

using (OracleCommand command = conn.CreateCommand())
{
    command.CommandText = "MY_GET_USERS";
    command.CommandType = CommandType.StoredProcedure;

    var curParameter = command.Parameters.Add(new OracleParameter()
    {
        ParameterName = "CUR",
        Direction = ParameterDirection.Output,
        OracleDbType = OracleDbType.RefCursor  // NOT OracleDbTypeEx
    });

    command.ExecuteNonQuery();

    OracleDataAdapter adapter = new OracleDataAdapter();
    adapter.Fill(ds, (OracleRefCursor)curParameter.Value);
}

Может показаться странным использовать ExecuteNonQuery для получения набора результатов, но результаты находятся в выходном параметре, а не в наборе результатов того же типа, что и вы.можно было бы позвонить ExecuteReader с SQL Server.

Обратите внимание на комментарий о свойствах OracleDbType и OracleDbTypeEx.Если вы установите свойство OracleDbTypeEx, свойство Value будет установлено на объект OracleDataReader.При установке свойства OracleDbType для свойства Value будет установлен объект OracleRefCursor, который adapter.Fill использует выше.Любой из них можно использовать, если вы хотите получить объект OracleDataReader и прочитать результаты самостоятельно.

// OracleDbType
using (var reader = ((OracleRefCursor)curParameter.Value).GetDataReader())

// OracleDbTypeEx
using (var reader = ((OracleDataReader)curParameter.Value))
...