using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; using Ordering.Infrastructure; using Ordering.Infrastructure.EntityConfigurations; using System; using System.Threading; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure { public class OrderingContext : DbContext,IUnitOfWork { public const string DEFAULT_SCHEMA = "ordering"; public DbSet Orders { get; set; } public DbSet OrderItems { get; set; } public DbSet Payments { get; set; } public DbSet Buyers { get; set; } public DbSet CardTypes { get; set; } public DbSet OrderStatus { get; set; } private readonly IMediator _mediator; private OrderingContext(DbContextOptions options) : base (options) { } public OrderingContext(DbContextOptions options, IMediator mediator) : base(options) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); System.Diagnostics.Debug.WriteLine("OrderingContext::ctor ->" + this.GetHashCode()); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfiguration(new ClientRequestEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new PaymentMethodEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new OrderEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration()); } public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)) { // Dispatch Domain Events collection. // Choices: // A) Right BEFORE committing data (EF SaveChanges) into the DB will make a single transaction including // side effects from the domain event handlers which are using the same DbContext with "InstancePerLifetimeScope" or "scoped" lifetime // B) Right AFTER committing data (EF SaveChanges) into the DB will make multiple transactions. // You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers. await _mediator.DispatchDomainEventsAsync(this); // After executing this line all the changes (from the Command Handler and Domain Event Handlers) // performed throught the DbContext will be commited var result = await base.SaveChangesAsync(); return true; } } public class OrderingContextDesignFactory : IDesignTimeDbContextFactory { public OrderingContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder() .UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;Integrated Security=true"); return new OrderingContext(optionsBuilder.Options,new NoMediator()); } class NoMediator : IMediator { public Task Publish(TNotification notification, CancellationToken cancellationToken = default(CancellationToken)) where TNotification : INotification { return Task.CompletedTask; } public Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) { return Task.FromResult(default(TResponse)); } public Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)) { return Task.CompletedTask; } } } }