Muflix
Muflix

Reputation: 6768

Sqlite in-memory - TransactionScope - ambient transaction has been detected

I am getting an exception

Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected

but I have no Idea how to workaround this exception. My code fails, when I call SaveChanges() inside TransactionScope. It is probably because TransactionScope itself is inside SQLite context transaction, but how to handle this issue ?

Method I want to test

it uses TransactionScope, because I want to be sure, that loaded object (Request class) will not change while I manipulate with him.

public void Handle(Create cmd)
{
    // Wrap via transaction
    using (var transaction = new TransactionScope(TransactionScopeOption.Required,
        new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
    {

        // Load request object from repository.
        Request request = _repository.Find(cmd.RequestId);

        // Create detail object
        var detail = new Detail(requestId: cmd.RequestId);

        // Add created detail object into Request object
        request.CreateDetail(detail);

        // Save request into repository.
        _repository.SaveChanges();                // <--- HERE IS THE EXCEPTION THROWN

        // Commit transaction
        transaction.Complete();
    }
}

Test method I want to execute It uses SQLite in-memory relation database, because TransactionScope does not support non-relation database.

[Fact]
public void Create()
{
    // Arrange
    // --------------------------------------------------------------------- 

    var request = new Request();

    using (var connection = new SqliteConnection("DataSource=:memory:"))
    {
        connection.Open();

        var options = new DbContextOptionsBuilder<SamplesContext>()
            .UseSqlite(connection)
            .Options;

        using (var context = new SamplesContext(options))
        {
            context.Database.EnsureCreated();

            var service = SetupDetailService(context);

            context.Request.Add(request);
            context.SaveChanges();

            var storedRequest = context.Request.FirstOrDefault();

            var createCommand = new Create(requestId: Convert.ToInt32(storedRequest.Id));

            // Act
            // --------------------------------------------------------------------- 
            service.Handle(createCommand);        // <--- HERE IS THE EXCEPTION THROWN
            context.SaveChanges();

            // Assert
            // ----------------------------------------------------------------------
            // ...

        };
    };

}

Upvotes: 3

Views: 2979

Answers (1)

jamie yiw
jamie yiw

Reputation: 471

I blocked the errors to get the tests running:

var builder = new DbContextOptionsBuilder<EpsOnlineDbContext>();
DbConnection connection = new SqliteConnection("DataSource=:memory:");
connection.OpenAsync().GetAwaiter().GetResult();
builder.UseSqlite(connection);
builder.ConfigureWarnings(x => x.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning));

Upvotes: 7

Related Questions