Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes committed despite active transaction and rollback in Oracle EF Core #445

Closed
cdMOE opened this issue Mar 19, 2025 · 4 comments
Closed

Comments

@cdMOE
Copy link

cdMOE commented Mar 19, 2025

EDIT
Read comment

Hello,

I encountered a situation where changes to the database are committed despite an active transaction, even when an error occurs and RollbackTransaction() is called.

The following code demonstrates the issue:

public class Worker(ILogger<Worker> logger, IServiceScopeFactory serviceScopeFactory) : BackgroundService
{
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var scope = serviceScopeFactory.CreateScope();
        var context = scope.ServiceProvider.GetRequiredService<MyContext>();

        var header = new Header
        {
            Id = 3,
            Data = "something"
        };

        context.Database.BeginTransaction();
        context.Headers.Add(header);
        context.SaveChanges();

        try
        {
            using var cmd = new OracleCommand(string.Empty, context.Database.GetDbConnection() as OracleConnection);
            var tablename = "sometable";
            
            // This will throw ORA-01031 (insufficient privileges)
            var createCommand = $"CREATE GLOBAL TEMPORARY TABLE {tablename} (something number)";
        
            cmd.CommandText = createCommand;
            cmd.ExecuteNonQuery();
        }
        catch (Exception e)
        {
            logger.LogError(e, "error");
            context.Database.RollbackTransaction();
            return Task.FromException(e);
        }

        context.Database.CommitTransaction();
        
        return Task.CompletedTask;
    }
}

Reproduction Steps

  1. Run the provided code with an Oracle database where the user does not have permission to create a table.
  2. Observe that an ORA-01031 exception is thrown.
  3. Check the database: the mytest_headers table still contains the inserted row.

Expected Behavior

Since a transaction was started using context.Database.BeginTransaction(), I expected the context.Headers.Add(header); operation to not be committed because:

  • The transaction was never explicitly committed.
  • RollbackTransaction() was called after the exception.

However, after inspecting the database, I see that the row was committed.

Reproducible Test Setup

Repro Project linked.

Table Creation

CREATE TABLE mytest_headers (
    ID NUMBER,
    Data VARCHAR2(50),
    PRIMARY KEY(Id)
);

Database User Setup

CREATE USER mytestuser IDENTIFIED BY mytest123;
GRANT CREATE SESSION TO mytestuser;
GRANT SELECT, INSERT ON mytest_headers TO mytestuser;

Environment

  • .net version: 8.0
  • Microsoft.EntityFrameworkCore Version 8.0.14
  • Oracle.EntityFrameworkCore Version 8.23.70
  • Oracle.ManagedDataAccess.Core" Version 23.7.0
  • Oracle DB Version: 19

ReproOracleCommand.zip

@cdMOE
Copy link
Author

cdMOE commented Mar 19, 2025

I just realized that this issue is not specific to the OracleException. The transaction was not being used correctly in the first place, so after the first SaveChanges() call, the changes were committed—regardless of whether the later ExecuteNonQuery() call succeeded or threw an exception. Apologies for the oversight.

I still wonder if there is a way to make ODP.NET and EF Core share the same transaction though, this is what challenges me.

@cdMOE cdMOE closed this as completed Mar 19, 2025
@cdMOE
Copy link
Author

cdMOE commented Mar 19, 2025

On second thought, I'm not sure if this behavior is expected. When calling SaveChanges() and then executing OracleCommand.ExecuteNonQuery(), the changes from SaveChanges() are committed immediately, rather than waiting for CommitTransaction() to be called.

Is this the intended behavior?

@cdMOE cdMOE reopened this Mar 19, 2025
@cdMOE cdMOE changed the title OracleCommand Changes committed despite active transaction and rollback in Oracle EF Core Changes committed despite active transaction and rollback in Oracle EF Core Mar 19, 2025
@alexkeh
Copy link
Member

alexkeh commented Mar 20, 2025

Oracle EF Core doesn't currently support DDL statements in transactions. A DDL in a transaction will commit everything up to and including the DDL.

If the transaction only had DML, then you would not see the commit occur prematurely.

@cdMOE
Copy link
Author

cdMOE commented Mar 20, 2025

Thank you for clarifying @alexkeh ! :)

@cdMOE cdMOE closed this as completed Mar 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants