Уведомление об изменении Oracle содержит недействительные действия

Настроить

Я создал консольное приложение для.NET 4.7.2 и установил пакет NuGet https://www.nuget.org/packages/Oracle.ManagedDataAccess/ версии 12.2.1100 (последняя / текущая), который устанавливает зависимость с двумя запросами для отслеживания изменений, внесенных в MYTABLEоба запроса имеют разные WHERE-предложения.

Сервер базы данных Oracle, к которому я подключаюсь, работает на localhost и имеет версию 12.2.0.1.0.

Рядом с консольным приложением, которое прослушивает уведомления, я использую Oracle SQL Developer (v18.1.0.095) для фактической вставки или обновления записей в MYTABLE для принудительного уведомления.

Код

using (var connection = new OracleConnection("Data Source=//localhost:1521/ORCL;Persist Security Info=True;User ID=SYSTEM;Password=password"))
{
    OracleDependency.Port = 3005;

    var dependency = new OracleDependency();
    dependency.OnChange += (sender, eventArgs) =>
    {
        Console.WriteLine($"Change count: {eventArgs.Details.Rows.Count}");

        // Columns in row: string ResourceName, int Info, string Rowid, long QueryId
        foreach (DataRow row in eventArgs.Details.Rows)
        {
            var resourceName = (string)row["ResourceName"];
            var info = (OracleNotificationInfo)row["Info"];
            var rowId = (string)row["rowid"];
            var queryId = (long)row["QueryId"];

            Console.WriteLine($"{queryId} {info} {rowId} {resourceName}");
        }
    };

    connection.Open();

    var command1 = new OracleCommand("SELECT * FROM MYTABLE WHERE NAME = 'N1'", connection);
    dependency.AddCommandDependency(command1);
    command1.Notification.IsNotifiedOnce = false;
    command1.AddRowid = true;
    command1.ExecuteNonQuery();

    var command2 = new OracleCommand("SELECT * FROM MYTABLE WHERE NAME = 'N2'", connection);
    dependency.AddCommandDependency(command2);
    command2.Notification.IsNotifiedOnce = false;
    command2.AddRowid = true;
    command2.ExecuteNonQuery();

    Console.ReadKey();
}

Поведение

Как только я запускаю несколько командных зависимостей в одной транзакции, я получаю в два раза больше строк событий в уведомлении и больше не могу различить queryid, который его запускает.

Выполнение этого запроса в одной транзакции:

INSERT INTO MYTABLE (NAME) VALUES ('N1');

выходы:

Change count: 1
63 Insert AAAR6CAABAAALohABJ SYSTEM.MYTABLE

Выполнение этого запроса в одной транзакции:

INSERT INTO MYTABLE (NAME) VALUES ('N2');

выходы:

Change count: 1
64 Insert AAAR6CAABAAALohABK SYSTEM.MYTABLE

Но при выполнении этого запроса в одной транзакции:

INSERT INTO MYTABLE (NAME) VALUES ('N1');
INSERT INTO MYTABLE (NAME) VALUES ('N2');

Я получаю этот вывод:

Change count: 4
63 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
63 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE

Пока я бы ожидал:

Change count: 2
63 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE

Кроме того, когда я делаю INSERT который запускает первую команду и UPDATE что запускает вторую команду, я получаю 4 строки с INSERT + UPDATE для первого QueryId (63) и INSERT + UPDATE для второго QueryId (64), так что теперь я могу отличить их.

Разделение командных зависимостей на несколько OracleDependency классы или даже множественные связи приводят к одному и тому же результату.

Интересно, кто-нибудь знает, что здесь происходит?

2 ответа

Возможно, использование одного и того же экземпляра OracleDependency с двумя OracleCommand приводит к такому поведению.

В разделе замечаний в документации Oracle для AddCommandDependency говорится, что это возможно, но это не похоже на конфигурацию по умолчанию.

Я бы предложил использовать два отдельных экземпляра OracleDependency. Мы не знаем, как агрегация двух запросов выполняется внутренне, но я предполагаю, что ODP.NET каким-то образом объединяет два запроса в один, используя синтаксис, который не поддерживается в "гарантированном" режиме.

Это может привести к тому, что уведомление будет использовать режим "наилучшего возможного", который, как указано в документах, склонен к ложным срабатываниям.

Кажется, нет способа узнать, какой режим используется при использовании ODP.NET, но я думаю, что режим автоматически определяется из запроса, и ограничения на запросы для каждого режима описаны здесь.

попробуйте проверить QueryBasedNotification of OracleDependency.

По умолчанию это свойство истинно. Разработчики ODP.NET могут регистрировать свои запросы на уровне строк, а не только на уровне объекта, начиная с Oracle Data Provider для .NET версии 11.1 и Oracle Database11g выпуска 1 (11.1). Приложение получает уведомление только тогда, когда выбранная строка или строки Уведомления на основе запросов предоставляют разработчикам большую степень детализации для использования кэшированных данных на стороне клиента, поскольку они могут быть более конкретными в отношении того, о каких изменениях необходимо уведомлять приложение.

Другие вопросы по тегам