Search code examples
c#.netentity-framework.net-coreonion-architecture

How can I access the Database field of a database context interface?


I'm using .NET Core 3.1. I have the following problem: I want to do a transaction in the Application layer. There I have a DbContext interface because I don't want to have access to the Infrastructure layer where I have the DbContext class. In other architectures I was able to access the Database field and therefore the Transaction because I was injecting the DbContext class. Now I'm injecting the DbContext interface I created and I don't know how to add the necessary fields that has as result the possible usage of Database field from the DbContext class. Here is the Infrastructure layer DbContext.

   public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>, IApplicationDbContext
   {
        private readonly ICurrentUserService _currentUserService;
        private readonly IDateTime _dateTime;
        public ApplicationDbContext(DbContextOptions options, ICurrentUserService currentUserService, IDateTime dateTime)
            : base(options)
        {
            _currentUserService = currentUserService;
            _dateTime = dateTime;
        }
        public DbSet<City> Cities { get; set; }
   }

And here is the Application layer DbContext interface.

    public interface IApplicationDbContext
    {
       Task<int> SaveChangesAsync(CancellationToken cancellationToken);
       public DbSet<City> Cities { get; set; }
    }

I want to be able to do something like this

   public class CityService
   {
      private readonly IApplicationDbContext _context;
      public CityService(IApplicationDbContext context)
      {
         _context = context;
      }
   public Task AddAsync(City city, CancellationToken cancellationToken)
   {
      using var transaction = _context.Database.BeginTransaction();
      try
      {
         await _context.AddAsync(city, cancellationToken);
         await _context.SaveChangesAsync(cancellationToken);
         await transaction.CommitAsync();
      }
      catch (Exception e)
      {
         await transaction.RollbackAsync();
      }
   }
   }

Solution

  • I found a solution for my problem. In the interface I added the following field:

    public DatabaseFacade Database { get; }
    

    After that I used it in the way I desired in the last code section from my question. Everything works like a charm! I don't know if it is the best way to do this but it works for me.