这是我第一次使用 DDD 来设计我的领域模型。我当前的域模型
Auction
看起来像这样:
public class Auction
{
public Guid Id { get; private set; }
public ApplicationUser Creator { get; private set; }
public DateTimeOffset CreatedAt { get; private set; }
public Stage Stage { get; private set; }
public ICollection<Bid> Bids { get; private set; } = new List<Bid>();
private Auction() { }
public static Auction Create(ApplicationUser creator, DateTimeOffset createdAt)
{
return new Auction
{
Id = Guid.NewGuid(),
Creator = creator,
CreatedAt = createdAt,
Stage = Stage.Active
};
}
public void PlaceBid(Bid bid)
{
if (BidIsGreaterThanCurrentHighestBid(bid) == false)
{
throw new InvalidBidException("Bid amount must be greater than the current highest bid.");
}
Bids.Add(bid);
}
private bool BidIsGreaterThanCurrentHighestBid(Bid bid)
{
var highestBid = Bids
.OrderByDescending(b => b.Amount)
.FirstOrDefault();
return highestBid == null || bid.Amount > highestBid.Amount;
}
}
我现在已经创建了一个命令来实际发出新的出价。这是命令处理程序的代码:
public class PlaceBidCommandHandler : IRequestHandler<PlaceBidCommand>
{
private readonly IApplicationDbContext _dbContext;
private readonly IIdentityService _identityService;
public PlaceBidCommandHandler(IApplicationDbContext dbContext,
IIdentityService identityService)
{
_dbContext = dbContext;
_identityService = identityService;
}
public async Task Handle(PlaceBidCommand request, CancellationToken cancellationToken)
{
var user = await _identityService.GetUserAsync();
var auction = await _dbContext.Auctions
.FirstOrDefaultAsync(a => a.Id == request.AuctionId, cancellationToken);
var bid = Bid.Create(user, auction, request.Amount);
auction.PlaceBid(bid);
_dbContext.Auctions.Entry(auction).State = EntityState.Modified;
await _dbContext.SaveChangesAsync(cancellationToken);
}
}
首先,通过手动设置状态来保存实体感觉不太合适。不管怎样,如果或者如果没有,代码就不起作用。
这是我得到的错误:
数据库操作预计影响 1 行,但实际影响 0 行。自加载实体以来,数据可能已被修改或删除。
编辑01:当我将命令处理程序更改为以下内容时,不会发生错误:
public async Task Handle(PlaceBidCommand request, CancellationToken cancellationToken)
{
var user = await _identityService.GetUserAsync();
var auction = await _dbContext.Auctions
.FirstOrDefaultAsync(a => a.Id == request.AuctionId, cancellationToken);
var bid = Bid.Create(user, auction, request.Amount);
await _dbContext.Bids.AddAsync(bid, cancellationToken);
await _dbContext.SaveChangesAsync(cancellationToken);
}
我不想这样添加出价。我想将其添加到我的拍卖模型中。
编辑 02: 这是我的 EF 映射:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>, IApplicationDbContext
{
public DbSet<Auction> Auctions => Set<Auction>();
public DbSet<Bid> Bids => Set<Bid>();
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Auction>()
.HasMany(e => e.Bids)
.WithOne(e => e.Auction)
.HasForeignKey("AuctionId")
.IsRequired();
modelBuilder.Entity<ApplicationUser>()
.HasMany(e => e.Auctions)
.WithOne(e => e.Creator)
.HasForeignKey("CreatorId")
.IsRequired();
modelBuilder.Entity<Bid>()
.HasOne(b => b.Bidder)
.WithMany();
modelBuilder.Entity<Bid>()
.HasOne(b => b.Auction)
.WithMany(a => a.Bids);
base.OnModelCreating(modelBuilder);
}
}
有人知道我该怎么做吗? - 我非常感谢任何形式的帮助! :)
正如Fran在评论中所说:
映射确实看起来很时髦。
经过一段时间,我终于找到了合适的解决方案。这里是
OnModelCreating()
方法的见解:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ----- Auction entity -----
modelBuilder.Entity<Auction>()
.HasKey(a => a.Id);
modelBuilder.Entity<Auction>()
.Property(a => a.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<Auction>()
.HasOne(a => a.Creator)
.WithMany(c => c.Auctions)
.HasForeignKey("CreatorId")
.IsRequired();
modelBuilder.Entity<Auction>()
.HasMany(a => a.Bids)
.WithOne(b => b.Auction)
.HasForeignKey("AuctionId")
.IsRequired();
// ----- Bid entity -----
modelBuilder.Entity<Bid>()
.HasKey(b => b.Id);
modelBuilder.Entity<Bid>()
.Property(b => b.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<Bid>()
.HasOne(b => b.Auction)
.WithMany(a => a.Bids)
.HasForeignKey("AuctionId")
.IsRequired();
modelBuilder.Entity<Bid>()
.HasOne(b => b.Bidder)
.WithMany()
.HasForeignKey("BidderId")
.IsRequired();
base.OnModelCreating(modelBuilder);
}i
我还将
Auction
实体更改为:
public class Auction
{
public Guid Id { get; private set; }
public ApplicationUser Creator { get; private set; }
public DateTimeOffset CreatedAt { get; private set; }
public Stage Stage { get; private set; }
private ICollection<Bid> _bids = new List<Bid>();
public IReadOnlyCollection<Bid> Bids => _bids.ToList().AsReadOnly();
private Auction() { }
public static Auction Create(ApplicationUser creator,
DateTimeOffset createdAt)
{
return new Auction
{
Creator = creator,
CreatedAt = createdAt,
Stage = Stage.Active
};
}
public void PlaceBid(Bid bid)
{
if (BidIsGreaterThanCurrentHighestBid(bid) == false)
{
throw new InvalidBidException("Bid amount must be greater than the current highest bid.");
}
_bids.Add(bid);
}
private bool BidIsGreaterThanCurrentHighestBid(Bid bid)
{
var highestBid = _bids
.OrderByDescending(b => b.Amount)
.FirstOrDefault();
return highestBid == null || bid.Amount > highestBid.Amount;
}
}
主要变化是:
PlaceBid()