修改实体时Entity Framework Core 错误

问题描述 投票:0回答:1

这是我第一次使用 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);
    }
}

有人知道我该怎么做吗? - 我非常感谢任何形式的帮助! :)

c# entity-framework entity-framework-core
1个回答
0
投票

正如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;
    }
}

主要变化是:

  1. 实体框架现在为我的实体生成 ID。
  2. 添加了支持字段,以便无法绕过该方法
    PlaceBid()
© www.soinside.com 2019 - 2024. All rights reserved.