EDIT (02/03/2018) : Since Entity Framework Core 2.1, EF Core implements transactions, cross-context transactions, ambient transactions and transactions scopes so this question is now out of date.
This is the official documentation about the transactions in EF Core : https://learn.microsoft.com/en-us/ef/core/saving/transactions.
How can I use the same transaction in differents methods ? The objective is to can commit or rollback all the modification if an error occurred.
I'm using Entity Framework Core version 1.1.0-preview1-final, and SQL Server 2014.
For example, I have an Entity Framework database context :
public class ApplicationDatabaseContext : DbContext
{
public ApplicationDatabaseContext(DbContextOptions<ApplicationDatabaseContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TransactionLog1>(entity =>
{
entity.ToTable("TRANSACTION_LOG_1");
entity.Property(e => e.CreationDate)
.HasColumnType("datetime")
.HasDefaultValueSql("getdate()");
});
modelBuilder.Entity<TransactionLog2>(entity =>
{
entity.ToTable("TRANSACTION_LOG_2");
entity.Property(e => e.CreationDate)
.HasColumnType("datetime")
.HasDefaultValueSql("getdate()");
});
}
public virtual DbSet<TransactionLog1> TransactionLog1 { get; set; }
public virtual DbSet<TransactionLog2> TransactionLog2 { get; set; }
}
And I have two classes to deal with data, the both are using the same context :
public interface IRepository1
{
void Create(Guid key);
}
public sealed class Repository1 : IRepository1
{
private readonly ApplicationDatabaseContext _dbContext;
public Repository1(ApplicationDatabaseContext dbcontext)
{
_dbContext = dbcontext;
}
public void Create(Guid key)
{
using (_dbContext.Database.BeginTransaction())
{
try
{
_dbContext.TransactionLog1.Add(new TransactionLog1 { Key = key });
_dbContext.SaveChanges();
_dbContext.Database.CommitTransaction();
}
catch (Exception)
{
throw;
}
}
}
}
public interface IRepository2
{
void Create(Guid key);
}
public sealed class Repository2 : IRepository2
{
private readonly ApplicationDatabaseContext _dbContext;
public Repository2(ApplicationDatabaseContext dbcontext)
{
_dbContext = dbcontext;
}
public void Create(Guid key)
{
using (_dbContext.Database.BeginTransaction())
{
try
{
_dbContext.TransactionLog2.Add(new TransactionLog2 { Key = key });
_dbContext.SaveChanges();
_dbContext.Database.CommitTransaction();
}
catch (Exception)
{
throw;
}
}
}
}
In my business logic, I have a service and I would like to call the method void Create(Guid key) on my first repository, then the same method from my second repository and commit only if the both occurred without error (if any error occurred in the secon method, I would like to rollback the commit done in the first method).
How can I do that ? What is the best practice with Entity Framework Core and transactions ?
I tried several things, like this, but it never works (with this method I have the error ) :
Warning as error exception for warning 'RelationalEventId.AmbientTransactionWarning': An ambient transaction has been detected. Entity Framework Core does not support ambient transactions.
public sealed class Service3 : IService3
{
private readonly IRepository1 _repo1;
private readonly IRepository2 _repo2;
public Service3(IRepository1 repo1, IRepository2 repo2)
{
_repo1 = repo1;
_repo2 = repo2;
}
public void Create(Guid key)
{
using (TransactionScope scope = new TransactionScope())
{
try
{
_repo1.Create(key);
_repo2.Create(key);
scope.Complete();
}
catch (Exception)
{
throw;
}
}
}
}
I read the documentation, espacially this page (https://learn.microsoft.com/en-us/ef/core/saving/transactions) but I don't have the method UseTransaction on Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.