3

Setup

I've created a Console application targeting .NET 4.7.2 and installed the NuGet package Oracle.ManagedDataAccess version 12.2.1100 (latest/current) that sets up a dependency with 2 queries to monitor changes made to MYTABLE, both queries have a different WHERE-clause.

The Oracle database server I'm connecting to is running on localhost and has version 12.2.0.1.0.

Next to the Console application that listens for notifications, I'm using Oracle SQL Developer (v18.1.0.095) to actually insert or update records to MYTABLE in order to force a notification.

Code

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

Behavior

As soon as I trigger multiple command dependencies in one transaction, I get twice as much event-rows in the notification and can no longer distinguish the queryid that triggers it.

Running this query in one transaction:

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

outputs:

Change count: 1
63 Insert AAAR6CAABAAALohABJ SYSTEM.MYTABLE

Running this query in one transaction:

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

outputs:

Change count: 1
64 Insert AAAR6CAABAAALohABK SYSTEM.MYTABLE

But, when running this query in one transaction:

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

I get this output:

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

While I would expect:

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

Also, when I do an INSERT that triggers the first command and an UPDATE that triggers the second command, I get 4 rows with INSERT + UPDATE for first QueryId (63) and INSERT + UPDATE for second QueryId (64), so now way I can tell them apart.

Separating the command dependencies over multiple OracleDependency classes or even multiple connections leads to the same outcome.

I wonder if someone knows what is going on here?

huysentruitw
  • 27,376
  • 9
  • 90
  • 133
  • As a sanity check, do the same inserts from sqlplus to make sure there's nothing going on with SQL Developer. Also, see if you can find out if any triggers are getting executed with these inserts as they could be causing side effects. – Christian Shay Jun 16 '18 at 15:49
  • @ChristianShay thanks for your comment. I've executed the same SQL statements from sqlplus.exe and the results are the same. I don't think any triggers are involved as this is a fresh database installation and a simple table I've created with an ID (number) and NAME (varchar2) column. – huysentruitw Jun 18 '18 at 07:01
  • Not that it would necessarily help, but i wonder now: if you run, let's say 3 and 4 INSERTs in the same transaction, do you get respectively 6 and 8 output lines, or 9 and 16? – jsanalytics Jun 18 '18 at 12:19
  • @jsanalytics 6 and 8. So the amount of changes is multiplied with the amount of command dependencies that were triggered. If I add a third command dependency and do 3 inserts (one per command dependency), I get 9 'changes' back. – huysentruitw Jun 18 '18 at 12:25
  • Did you just answer your own question then? – jsanalytics Jun 18 '18 at 13:50
  • No, because that's exactly the problem. If I do an UPDATE that triggers dependency 1, and an INSERT that triggers dependency 2, you can no longer distinguish for which dependency the INSERT or UPDATE was triggered. – huysentruitw Jun 18 '18 at 14:56
  • The change notifications are not guaranteed to just notify on what is relevant. Take a look at answers to this question: < https://stackoverflow.com/questions/25199325 > – Hilarion Jun 22 '18 at 18:57
  • The documentation says that false positives can occur in best effort mode, which in turn is choosen when the query is complex. While there's no definition of 'complex', I can't imagine this simple where clause is considered complex, or is it? – huysentruitw Jun 22 '18 at 19:55

2 Answers2

0

Maybe using the same OracleDependency instance with two OracleCommand is leading to this behavior.

The remarks section in the Oracle docs for AddCommandDependency is saying that this is possible, but it doesn't seem to be the default configuration.

I would suggest using two separate OracleDependency instances. We don't know how the aggregation of the two queries is done internally, but I'm guessing maybe ODP.NET is somehow aggregating the two queries into one, using a syntax that is unsupported in "guaranteed" mode.

This can cause the notification to use the "best-effort" mode, which is stated in the docs to be prone to false positives.

There doesn't seem to be a way of knowing which mode is used when using ODP.NET, but I would guess the mode is autodetected from the query, and the constraints on queries for each mode are documented here.

GotGot
  • 1
  • 1
  • 1
  • Two separate oracle dependencies on the same connection give the same result. Even using two separate oracle connections give me the same result as in my question, so I think we can rule out ODP.NET. – huysentruitw Jun 25 '18 at 07:05
  • Have you checked also the constraints regarding queries ? On thing that I can thinks of is that you are using "SELECT *", and the linked doc state that "guaranteed" mode need that "Every column that it references is either a NUMBER data type or a VARCHAR2 data type." Do you really need to watch for changes on every column, and are all your columns of either type ? Maybe for testing purpose select only one column and see how this goes. – GotGot Jun 25 '18 at 09:16
  • Yes, this is a test table with only 2 columns, a NUMBER (ID) and a VARCHAR2 column (NAME). – huysentruitw Jun 25 '18 at 09:18
0

try to check QueryBasedNotification of OracleDependency.

By default, this property is true. ODP.NET developers can register their queries on the row level, not just the object level, beginning with Oracle Data Provider for .NET release 11.1 and Oracle Database 11g release 1(11.1).The application only receives notification when the selected row or rows change.Query - based notifications provide developers more granularity for using client-side cached data, as they can be more specific about what changes the application needs to be notified of