Refactored namespaces for ordering.infrastructure project

This commit is contained in:
Sumit Ghosh 2021-10-09 17:39:07 +05:30
parent 0c52323f8d
commit c007047291
13 changed files with 437 additions and 525 deletions

View File

@ -1,41 +1,35 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
namespace Ordering.Infrastructure.EntityConfigurations class BuyerEntityTypeConfiguration
: IEntityTypeConfiguration<Buyer>
{ {
class BuyerEntityTypeConfiguration public void Configure(EntityTypeBuilder<Buyer> buyerConfiguration)
: IEntityTypeConfiguration<Buyer>
{ {
public void Configure(EntityTypeBuilder<Buyer> buyerConfiguration) buyerConfiguration.ToTable("buyers", OrderingContext.DEFAULT_SCHEMA);
{
buyerConfiguration.ToTable("buyers", OrderingContext.DEFAULT_SCHEMA);
buyerConfiguration.HasKey(b => b.Id); buyerConfiguration.HasKey(b => b.Id);
buyerConfiguration.Ignore(b => b.DomainEvents); buyerConfiguration.Ignore(b => b.DomainEvents);
buyerConfiguration.Property(b => b.Id) buyerConfiguration.Property(b => b.Id)
.UseHiLo("buyerseq", OrderingContext.DEFAULT_SCHEMA); .UseHiLo("buyerseq", OrderingContext.DEFAULT_SCHEMA);
buyerConfiguration.Property(b => b.IdentityGuid) buyerConfiguration.Property(b => b.IdentityGuid)
.HasMaxLength(200) .HasMaxLength(200)
.IsRequired(); .IsRequired();
buyerConfiguration.HasIndex("IdentityGuid") buyerConfiguration.HasIndex("IdentityGuid")
.IsUnique(true); .IsUnique(true);
buyerConfiguration.Property(b => b.Name); buyerConfiguration.Property(b => b.Name);
buyerConfiguration.HasMany(b => b.PaymentMethods) buyerConfiguration.HasMany(b => b.PaymentMethods)
.WithOne() .WithOne()
.HasForeignKey("BuyerId") .HasForeignKey("BuyerId")
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
var navigation = buyerConfiguration.Metadata.FindNavigation(nameof(Buyer.PaymentMethods)); var navigation = buyerConfiguration.Metadata.FindNavigation(nameof(Buyer.PaymentMethods));
navigation.SetPropertyAccessMode(PropertyAccessMode.Field); navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
}
} }
} }

View File

@ -1,27 +1,21 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
namespace Ordering.Infrastructure.EntityConfigurations class CardTypeEntityTypeConfiguration
: IEntityTypeConfiguration<CardType>
{ {
class CardTypeEntityTypeConfiguration public void Configure(EntityTypeBuilder<CardType> cardTypesConfiguration)
: IEntityTypeConfiguration<CardType>
{ {
public void Configure(EntityTypeBuilder<CardType> cardTypesConfiguration) cardTypesConfiguration.ToTable("cardtypes", OrderingContext.DEFAULT_SCHEMA);
{
cardTypesConfiguration.ToTable("cardtypes", OrderingContext.DEFAULT_SCHEMA);
cardTypesConfiguration.HasKey(ct => ct.Id); cardTypesConfiguration.HasKey(ct => ct.Id);
cardTypesConfiguration.Property(ct => ct.Id) cardTypesConfiguration.Property(ct => ct.Id)
.HasDefaultValue(1) .HasDefaultValue(1)
.ValueGeneratedNever() .ValueGeneratedNever()
.IsRequired(); .IsRequired();
cardTypesConfiguration.Property(ct => ct.Name) cardTypesConfiguration.Property(ct => ct.Name)
.HasMaxLength(200) .HasMaxLength(200)
.IsRequired(); .IsRequired();
}
} }
} }

View File

@ -1,19 +1,13 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
namespace Ordering.Infrastructure.EntityConfigurations class ClientRequestEntityTypeConfiguration
: IEntityTypeConfiguration<ClientRequest>
{ {
class ClientRequestEntityTypeConfiguration public void Configure(EntityTypeBuilder<ClientRequest> requestConfiguration)
: IEntityTypeConfiguration<ClientRequest>
{ {
public void Configure(EntityTypeBuilder<ClientRequest> requestConfiguration) requestConfiguration.ToTable("requests", OrderingContext.DEFAULT_SCHEMA);
{ requestConfiguration.HasKey(cr => cr.Id);
requestConfiguration.ToTable("requests", OrderingContext.DEFAULT_SCHEMA); requestConfiguration.Property(cr => cr.Name).IsRequired();
requestConfiguration.HasKey(cr => cr.Id); requestConfiguration.Property(cr => cr.Time).IsRequired();
requestConfiguration.Property(cr => cr.Name).IsRequired();
requestConfiguration.Property(cr => cr.Time).IsRequired();
}
} }
} }

View File

@ -1,86 +1,78 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using System;
namespace Ordering.Infrastructure.EntityConfigurations class OrderEntityTypeConfiguration : IEntityTypeConfiguration<Order>
{ {
class OrderEntityTypeConfiguration : IEntityTypeConfiguration<Order> public void Configure(EntityTypeBuilder<Order> orderConfiguration)
{ {
public void Configure(EntityTypeBuilder<Order> orderConfiguration) orderConfiguration.ToTable("orders", OrderingContext.DEFAULT_SCHEMA);
{
orderConfiguration.ToTable("orders", OrderingContext.DEFAULT_SCHEMA);
orderConfiguration.HasKey(o => o.Id); orderConfiguration.HasKey(o => o.Id);
orderConfiguration.Ignore(b => b.DomainEvents); orderConfiguration.Ignore(b => b.DomainEvents);
orderConfiguration.Property(o => o.Id) orderConfiguration.Property(o => o.Id)
.UseHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA);
//Address value object persisted as owned entity type supported since EF Core 2.0
orderConfiguration
.OwnsOne(o => o.Address, a =>
{
// Explicit configuration of the shadow key property in the owned type
// as a workaround for a documented issue in EF Core 5: https://github.com/dotnet/efcore/issues/20740
a.Property<int>("OrderId")
.UseHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA); .UseHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA);
a.WithOwner();
});
//Address value object persisted as owned entity type supported since EF Core 2.0 orderConfiguration
orderConfiguration .Property<int?>("_buyerId")
.OwnsOne(o => o.Address, a => .UsePropertyAccessMode(PropertyAccessMode.Field)
{ .HasColumnName("BuyerId")
// Explicit configuration of the shadow key property in the owned type .IsRequired(false);
// as a workaround for a documented issue in EF Core 5: https://github.com/dotnet/efcore/issues/20740
a.Property<int>("OrderId")
.UseHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA);
a.WithOwner();
});
orderConfiguration orderConfiguration
.Property<int?>("_buyerId") .Property<DateTime>("_orderDate")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("BuyerId") .HasColumnName("OrderDate")
.IsRequired(false); .IsRequired();
orderConfiguration orderConfiguration
.Property<DateTime>("_orderDate") .Property<int>("_orderStatusId")
.UsePropertyAccessMode(PropertyAccessMode.Field) // .HasField("_orderStatusId")
.HasColumnName("OrderDate") .UsePropertyAccessMode(PropertyAccessMode.Field)
.IsRequired(); .HasColumnName("OrderStatusId")
.IsRequired();
orderConfiguration orderConfiguration
.Property<int>("_orderStatusId") .Property<int?>("_paymentMethodId")
// .HasField("_orderStatusId") .UsePropertyAccessMode(PropertyAccessMode.Field)
.UsePropertyAccessMode(PropertyAccessMode.Field) .HasColumnName("PaymentMethodId")
.HasColumnName("OrderStatusId") .IsRequired(false);
.IsRequired();
orderConfiguration orderConfiguration.Property<string>("Description").IsRequired(false);
.Property<int?>("_paymentMethodId")
.UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("PaymentMethodId")
.IsRequired(false);
orderConfiguration.Property<string>("Description").IsRequired(false); var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems));
var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems)); // DDD Patterns comment:
//Set as field (New since EF 1.1) to access the OrderItem collection property through its field
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
// DDD Patterns comment: orderConfiguration.HasOne<PaymentMethod>()
//Set as field (New since EF 1.1) to access the OrderItem collection property through its field .WithMany()
navigation.SetPropertyAccessMode(PropertyAccessMode.Field); // .HasForeignKey("PaymentMethodId")
.HasForeignKey("_paymentMethodId")
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
orderConfiguration.HasOne<PaymentMethod>() orderConfiguration.HasOne<Buyer>()
.WithMany() .WithMany()
// .HasForeignKey("PaymentMethodId") .IsRequired(false)
.HasForeignKey("_paymentMethodId") // .HasForeignKey("BuyerId");
.IsRequired(false) .HasForeignKey("_buyerId");
.OnDelete(DeleteBehavior.Restrict);
orderConfiguration.HasOne<Buyer>() orderConfiguration.HasOne(o => o.OrderStatus)
.WithMany() .WithMany()
.IsRequired(false) // .HasForeignKey("OrderStatusId");
// .HasForeignKey("BuyerId"); .HasForeignKey("_orderStatusId");
.HasForeignKey("_buyerId");
orderConfiguration.HasOne(o => o.OrderStatus)
.WithMany()
// .HasForeignKey("OrderStatusId");
.HasForeignKey("_orderStatusId");
}
} }
} }

View File

@ -1,59 +1,53 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
namespace Ordering.Infrastructure.EntityConfigurations class OrderItemEntityTypeConfiguration
: IEntityTypeConfiguration<OrderItem>
{ {
class OrderItemEntityTypeConfiguration public void Configure(EntityTypeBuilder<OrderItem> orderItemConfiguration)
: IEntityTypeConfiguration<OrderItem>
{ {
public void Configure(EntityTypeBuilder<OrderItem> orderItemConfiguration) orderItemConfiguration.ToTable("orderItems", OrderingContext.DEFAULT_SCHEMA);
{
orderItemConfiguration.ToTable("orderItems", OrderingContext.DEFAULT_SCHEMA);
orderItemConfiguration.HasKey(o => o.Id); orderItemConfiguration.HasKey(o => o.Id);
orderItemConfiguration.Ignore(b => b.DomainEvents); orderItemConfiguration.Ignore(b => b.DomainEvents);
orderItemConfiguration.Property(o => o.Id) orderItemConfiguration.Property(o => o.Id)
.UseHiLo("orderitemseq"); .UseHiLo("orderitemseq");
orderItemConfiguration.Property<int>("OrderId") orderItemConfiguration.Property<int>("OrderId")
.IsRequired(); .IsRequired();
orderItemConfiguration orderItemConfiguration
.Property<decimal>("_discount") .Property<decimal>("_discount")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("Discount") .HasColumnName("Discount")
.IsRequired(); .IsRequired();
orderItemConfiguration.Property<int>("ProductId") orderItemConfiguration.Property<int>("ProductId")
.IsRequired(); .IsRequired();
orderItemConfiguration orderItemConfiguration
.Property<string>("_productName") .Property<string>("_productName")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("ProductName") .HasColumnName("ProductName")
.IsRequired(); .IsRequired();
orderItemConfiguration orderItemConfiguration
.Property<decimal>("_unitPrice") .Property<decimal>("_unitPrice")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("UnitPrice") .HasColumnName("UnitPrice")
.IsRequired(); .IsRequired();
orderItemConfiguration orderItemConfiguration
.Property<int>("_units") .Property<int>("_units")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("Units") .HasColumnName("Units")
.IsRequired(); .IsRequired();
orderItemConfiguration orderItemConfiguration
.Property<string>("_pictureUrl") .Property<string>("_pictureUrl")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("PictureUrl") .HasColumnName("PictureUrl")
.IsRequired(false); .IsRequired(false);
}
} }
} }

View File

@ -1,27 +1,21 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
namespace Ordering.Infrastructure.EntityConfigurations class OrderStatusEntityTypeConfiguration
: IEntityTypeConfiguration<OrderStatus>
{ {
class OrderStatusEntityTypeConfiguration public void Configure(EntityTypeBuilder<OrderStatus> orderStatusConfiguration)
: IEntityTypeConfiguration<OrderStatus>
{ {
public void Configure(EntityTypeBuilder<OrderStatus> orderStatusConfiguration) orderStatusConfiguration.ToTable("orderstatus", OrderingContext.DEFAULT_SCHEMA);
{
orderStatusConfiguration.ToTable("orderstatus", OrderingContext.DEFAULT_SCHEMA);
orderStatusConfiguration.HasKey(o => o.Id); orderStatusConfiguration.HasKey(o => o.Id);
orderStatusConfiguration.Property(o => o.Id) orderStatusConfiguration.Property(o => o.Id)
.HasDefaultValue(1) .HasDefaultValue(1)
.ValueGeneratedNever() .ValueGeneratedNever()
.IsRequired(); .IsRequired();
orderStatusConfiguration.Property(o => o.Name) orderStatusConfiguration.Property(o => o.Name)
.HasMaxLength(200) .HasMaxLength(200)
.IsRequired(); .IsRequired();
}
} }
} }

View File

@ -1,65 +1,58 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using System;
namespace Ordering.Infrastructure.EntityConfigurations class PaymentMethodEntityTypeConfiguration
: IEntityTypeConfiguration<PaymentMethod>
{ {
class PaymentMethodEntityTypeConfiguration public void Configure(EntityTypeBuilder<PaymentMethod> paymentConfiguration)
: IEntityTypeConfiguration<PaymentMethod>
{ {
public void Configure(EntityTypeBuilder<PaymentMethod> paymentConfiguration) paymentConfiguration.ToTable("paymentmethods", OrderingContext.DEFAULT_SCHEMA);
{
paymentConfiguration.ToTable("paymentmethods", OrderingContext.DEFAULT_SCHEMA);
paymentConfiguration.HasKey(b => b.Id); paymentConfiguration.HasKey(b => b.Id);
paymentConfiguration.Ignore(b => b.DomainEvents); paymentConfiguration.Ignore(b => b.DomainEvents);
paymentConfiguration.Property(b => b.Id) paymentConfiguration.Property(b => b.Id)
.UseHiLo("paymentseq", OrderingContext.DEFAULT_SCHEMA); .UseHiLo("paymentseq", OrderingContext.DEFAULT_SCHEMA);
paymentConfiguration.Property<int>("BuyerId") paymentConfiguration.Property<int>("BuyerId")
.IsRequired(); .IsRequired();
paymentConfiguration paymentConfiguration
.Property<string>("_cardHolderName") .Property<string>("_cardHolderName")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("CardHolderName") .HasColumnName("CardHolderName")
.HasMaxLength(200) .HasMaxLength(200)
.IsRequired(); .IsRequired();
paymentConfiguration paymentConfiguration
.Property<string>("_alias") .Property<string>("_alias")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("Alias") .HasColumnName("Alias")
.HasMaxLength(200) .HasMaxLength(200)
.IsRequired(); .IsRequired();
paymentConfiguration paymentConfiguration
.Property<string>("_cardNumber") .Property<string>("_cardNumber")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("CardNumber") .HasColumnName("CardNumber")
.HasMaxLength(25) .HasMaxLength(25)
.IsRequired(); .IsRequired();
paymentConfiguration paymentConfiguration
.Property<DateTime>("_expiration") .Property<DateTime>("_expiration")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("Expiration") .HasColumnName("Expiration")
.HasMaxLength(25) .HasMaxLength(25)
.IsRequired(); .IsRequired();
paymentConfiguration paymentConfiguration
.Property<int>("_cardTypeId") .Property<int>("_cardTypeId")
.UsePropertyAccessMode(PropertyAccessMode.Field) .UsePropertyAccessMode(PropertyAccessMode.Field)
.HasColumnName("CardTypeId") .HasColumnName("CardTypeId")
.IsRequired(); .IsRequired();
paymentConfiguration.HasOne(p => p.CardType) paymentConfiguration.HasOne(p => p.CardType)
.WithMany() .WithMany()
.HasForeignKey("_cardTypeId"); .HasForeignKey("_cardTypeId");
}
} }
} }

View File

@ -1,11 +1,8 @@
using System; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency public class ClientRequest
{ {
public class ClientRequest public Guid Id { get; set; }
{ public string Name { get; set; }
public Guid Id { get; set; } public DateTime Time { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
}
} }

View File

@ -1,12 +1,8 @@
using System; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency public interface IRequestManager
{ {
public interface IRequestManager Task<bool> ExistAsync(Guid id);
{
Task<bool> ExistAsync(Guid id);
Task CreateRequestForCommandAsync<T>(Guid id); Task CreateRequestForCommandAsync<T>(Guid id);
}
} }

View File

@ -1,43 +1,38 @@
using Ordering.Domain.Exceptions; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency public class RequestManager : IRequestManager
{ {
public class RequestManager : IRequestManager private readonly OrderingContext _context;
public RequestManager(OrderingContext context)
{ {
private readonly OrderingContext _context; _context = context ?? throw new ArgumentNullException(nameof(context));
}
public RequestManager(OrderingContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public async Task<bool> ExistAsync(Guid id) public async Task<bool> ExistAsync(Guid id)
{ {
var request = await _context. var request = await _context.
FindAsync<ClientRequest>(id); FindAsync<ClientRequest>(id);
return request != null; return request != null;
} }
public async Task CreateRequestForCommandAsync<T>(Guid id) public async Task CreateRequestForCommandAsync<T>(Guid id)
{ {
var exists = await ExistAsync(id); var exists = await ExistAsync(id);
var request = exists ? var request = exists ?
throw new OrderingDomainException($"Request with {id} already exists") : throw new OrderingDomainException($"Request with {id} already exists") :
new ClientRequest() new ClientRequest()
{ {
Id = id, Id = id,
Name = typeof(T).Name, Name = typeof(T).Name,
Time = DateTime.UtcNow Time = DateTime.UtcNow
}; };
_context.Add(request); _context.Add(request);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
}
} }
} }

View File

@ -1,156 +1,141 @@
using MediatR; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Storage;
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.Data;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure public class OrderingContext : DbContext, IUnitOfWork
{ {
public class OrderingContext : DbContext, IUnitOfWork public const string DEFAULT_SCHEMA = "ordering";
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<PaymentMethod> Payments { get; set; }
public DbSet<Buyer> Buyers { get; set; }
public DbSet<CardType> CardTypes { get; set; }
public DbSet<OrderStatus> OrderStatus { get; set; }
private readonly IMediator _mediator;
private IDbContextTransaction _currentTransaction;
public OrderingContext(DbContextOptions<OrderingContext> options) : base(options) { }
public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;
public bool HasActiveTransaction => _currentTransaction != null;
public OrderingContext(DbContextOptions<OrderingContext> options, IMediator mediator) : base(options)
{ {
public const string DEFAULT_SCHEMA = "ordering"; _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<PaymentMethod> Payments { get; set; }
public DbSet<Buyer> Buyers { get; set; }
public DbSet<CardType> CardTypes { get; set; }
public DbSet<OrderStatus> OrderStatus { get; set; }
private readonly IMediator _mediator;
private IDbContextTransaction _currentTransaction;
public OrderingContext(DbContextOptions<OrderingContext> options) : base(options) { } System.Diagnostics.Debug.WriteLine("OrderingContext::ctor ->" + this.GetHashCode());
}
public IDbContextTransaction GetCurrentTransaction() => _currentTransaction; 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 bool HasActiveTransaction => _currentTransaction != null; public async Task<bool> 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);
public OrderingContext(DbContextOptions<OrderingContext> options, IMediator mediator) : base(options) // After executing this line all the changes (from the Command Handler and Domain Event Handlers)
// performed through the DbContext will be committed
var result = await base.SaveChangesAsync(cancellationToken);
return true;
}
public async Task<IDbContextTransaction> BeginTransactionAsync()
{
if (_currentTransaction != null) return null;
_currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
return _currentTransaction;
}
public async Task CommitTransactionAsync(IDbContextTransaction transaction)
{
if (transaction == null) throw new ArgumentNullException(nameof(transaction));
if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
try
{ {
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); await SaveChangesAsync();
transaction.Commit();
System.Diagnostics.Debug.WriteLine("OrderingContext::ctor ->" + this.GetHashCode());
} }
catch
protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
modelBuilder.ApplyConfiguration(new ClientRequestEntityTypeConfiguration()); RollbackTransaction();
modelBuilder.ApplyConfiguration(new PaymentMethodEntityTypeConfiguration()); throw;
modelBuilder.ApplyConfiguration(new OrderEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new OrderItemEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new CardTypeEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new OrderStatusEntityTypeConfiguration());
modelBuilder.ApplyConfiguration(new BuyerEntityTypeConfiguration());
} }
finally
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
{ {
// Dispatch Domain Events collection. if (_currentTransaction != null)
// 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 through the DbContext will be committed
var result = await base.SaveChangesAsync(cancellationToken);
return true;
}
public async Task<IDbContextTransaction> BeginTransactionAsync()
{
if (_currentTransaction != null) return null;
_currentTransaction = await Database.BeginTransactionAsync(IsolationLevel.ReadCommitted);
return _currentTransaction;
}
public async Task CommitTransactionAsync(IDbContextTransaction transaction)
{
if (transaction == null) throw new ArgumentNullException(nameof(transaction));
if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
try
{ {
await SaveChangesAsync(); _currentTransaction.Dispose();
transaction.Commit(); _currentTransaction = null;
}
catch
{
RollbackTransaction();
throw;
}
finally
{
if (_currentTransaction != null)
{
_currentTransaction.Dispose();
_currentTransaction = null;
}
}
}
public void RollbackTransaction()
{
try
{
_currentTransaction?.Rollback();
}
finally
{
if (_currentTransaction != null)
{
_currentTransaction.Dispose();
_currentTransaction = null;
}
} }
} }
} }
public class OrderingContextDesignFactory : IDesignTimeDbContextFactory<OrderingContext> public void RollbackTransaction()
{ {
public OrderingContext CreateDbContext(string[] args) try
{ {
var optionsBuilder = new DbContextOptionsBuilder<OrderingContext>() _currentTransaction?.Rollback();
.UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;Integrated Security=true");
return new OrderingContext(optionsBuilder.Options, new NoMediator());
} }
finally
class NoMediator : IMediator
{ {
public Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default(CancellationToken)) where TNotification : INotification if (_currentTransaction != null)
{ {
return Task.CompletedTask; _currentTransaction.Dispose();
} _currentTransaction = null;
public Task Publish(object notification, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult<TResponse>(default(TResponse));
}
public Task<object> Send(object request, CancellationToken cancellationToken = default)
{
return Task.FromResult(default(object));
} }
} }
} }
} }
public class OrderingContextDesignFactory : IDesignTimeDbContextFactory<OrderingContext>
{
public OrderingContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<OrderingContext>()
.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>(TNotification notification, CancellationToken cancellationToken = default(CancellationToken)) where TNotification : INotification
{
return Task.CompletedTask;
}
public Task Publish(object notification, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult<TResponse>(default(TResponse));
}
public Task<object> Send(object request, CancellationToken cancellationToken = default)
{
return Task.FromResult(default(object));
}
}
}

View File

@ -1,68 +1,60 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories public class BuyerRepository
: IBuyerRepository
{ {
public class BuyerRepository private readonly OrderingContext _context;
: IBuyerRepository public IUnitOfWork UnitOfWork
{ {
private readonly OrderingContext _context; get
public IUnitOfWork UnitOfWork
{ {
get return _context;
{
return _context;
}
} }
}
public BuyerRepository(OrderingContext context) public BuyerRepository(OrderingContext context)
{ {
_context = context ?? throw new ArgumentNullException(nameof(context)); _context = context ?? throw new ArgumentNullException(nameof(context));
} }
public Buyer Add(Buyer buyer) public Buyer Add(Buyer buyer)
{ {
if (buyer.IsTransient()) if (buyer.IsTransient())
{
return _context.Buyers
.Add(buyer)
.Entity;
}
else
{
return buyer;
}
}
public Buyer Update(Buyer buyer)
{ {
return _context.Buyers return _context.Buyers
.Update(buyer) .Add(buyer)
.Entity; .Entity;
} }
else
public async Task<Buyer> FindAsync(string identity)
{ {
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.IdentityGuid == identity)
.SingleOrDefaultAsync();
return buyer;
}
public async Task<Buyer> FindByIdAsync(string id)
{
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.Id == int.Parse(id))
.SingleOrDefaultAsync();
return buyer; return buyer;
} }
} }
public Buyer Update(Buyer buyer)
{
return _context.Buyers
.Update(buyer)
.Entity;
}
public async Task<Buyer> FindAsync(string identity)
{
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.IdentityGuid == identity)
.SingleOrDefaultAsync();
return buyer;
}
public async Task<Buyer> FindByIdAsync(string id)
{
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.Id == int.Parse(id))
.SingleOrDefaultAsync();
return buyer;
}
} }

View File

@ -1,63 +1,55 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories public class OrderRepository
: IOrderRepository
{ {
public class OrderRepository private readonly OrderingContext _context;
: IOrderRepository
public IUnitOfWork UnitOfWork
{ {
private readonly OrderingContext _context; get
public IUnitOfWork UnitOfWork
{ {
get return _context;
{
return _context;
}
}
public OrderRepository(OrderingContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public Order Add(Order order)
{
return _context.Orders.Add(order).Entity;
}
public async Task<Order> GetAsync(int orderId)
{
var order = await _context
.Orders
.Include(x => x.Address)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order == null)
{
order = _context
.Orders
.Local
.FirstOrDefault(o => o.Id == orderId);
}
if (order != null)
{
await _context.Entry(order)
.Collection(i => i.OrderItems).LoadAsync();
await _context.Entry(order)
.Reference(i => i.OrderStatus).LoadAsync();
}
return order;
}
public void Update(Order order)
{
_context.Entry(order).State = EntityState.Modified;
} }
} }
public OrderRepository(OrderingContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public Order Add(Order order)
{
return _context.Orders.Add(order).Entity;
}
public async Task<Order> GetAsync(int orderId)
{
var order = await _context
.Orders
.Include(x => x.Address)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order == null)
{
order = _context
.Orders
.Local
.FirstOrDefault(o => o.Id == orderId);
}
if (order != null)
{
await _context.Entry(order)
.Collection(i => i.OrderItems).LoadAsync();
await _context.Entry(order)
.Reference(i => i.OrderStatus).LoadAsync();
}
return order;
}
public void Update(Order order)
{
_context.Entry(order).State = EntityState.Modified;
}
} }