Entity Framework 核心不保存更新

Entity Framework Core not saving updates

我有一个绘画网络应用程序,它使用 ASP.NET Core、Angular、EF Core、SQL 服务器、带有存储库模式的 AutoMapper。

问题是,当我尝试从绘画 table 更新单个绘画时,它没有保存到数据库中。我用同样的方法尝试了其他 tables 以查看是否是流程问题,但它们成功保存。

通过 swagger 我调用了 put 方法,这调用了绘画控制器,进入存储库,存储库 returns 更新的对象但是当我进入数据库时​​没有任何更新。如果我大摇大摆地调用 get 操作,我也看不到更新。

当我添加断点以查看数据时,从头到尾一切看​​起来都很好,但它只是没有保存到数据库中。为了测试,我什至尝试删除自动映射器逻辑并在更新方法中手动创建一个对象,并将现有对象属性设置为这些硬编码值以查看它是传入数据,但仍然没有成功。同样,为了测试,我尝试更新其他 tables 并且那些有效。

控制器

[HttpPut("{paintingId:int}")]
public async Task<IActionResult> UpdatePaintingAsync(int paintingId, [FromBody] UpdatePaintingRequest updatePaintingRequest)
{
    try
    {
        if (await repository.Exists(paintingId))
        {
            var updatedPaiting = await repository.UpdatePainting(paintingId, mapper.Map<DataModels.Painting>(updatePaintingRequest));

            if (updatedPaiting != null)
            {
                return Ok(updatePaintingRequest);
            }
        }

        return NotFound();
    }
    catch (Exception ex)
    {
        logger.LogError($"Failed to update painting: {ex}");
        return BadRequest("Failed to update painting");
    }
}

从存储库更新方法

public async Task<Painting> UpdatePainting(int paintingId, Painting request)
{
    var existingPainting = await GetPaintingByIdAsync(paintingId);

    if (existingPainting != null)
    {
        existingPainting.Name = request.Name;
        existingPainting.Description = request.Description;
        existingPainting.ImageUrl = request.ImageUrl;
        existingPainting.IsOriginalAvailable = request.IsOriginalAvailable;
        existingPainting.IsPrintAvailable = request.IsPrintAvailable;
        existingPainting.IsActive = request.IsActive;

        await context.SaveChangesAsync();

        return existingPainting;
    }

    return null;
}

获取绘画进行更新

public async Task<Painting> GetPaintingByIdAsync(int paintingId)
{
    return await context.Painting
        .Include(x => x.PaintingCategories)
        .ThenInclude(c => c.Category)
        .AsNoTracking()
        .Where(x => x.PaintingId == paintingId)
        .FirstOrDefaultAsync();
}

模型(在 DAO 和 DTO 上完全相同)

public class Painting
{
    public int PaintingId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string ImageUrl { get; set; }
    public bool IsOriginalAvailable { get; set; }
    public bool IsPrintAvailable { get; set; }
    public bool IsActive { get; set; }
    public ICollection<PaintingCategory> PaintingCategories { get; set; }
}

上下文

public class JonathanKrownContext : DbContext
{
    public JonathanKrownContext(DbContextOptions<JonathanKrownContext> options) : base(options)
    {
    }

    public DbSet<Painting> Painting { get; set; }
}

ModelBuilder.Entity

modelBuilder.Entity("JonathanKrownArt.API.DataModels.Painting", b =>
    {
        b.Property<int>("PaintingId")
            .ValueGeneratedOnAdd()
            .HasColumnType("int")
            .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

        b.Property<string>("Description")
            .HasColumnType("nvarchar(max)");

        b.Property<string>("ImageUrl")
            .HasColumnType("nvarchar(max)");

        b.Property<bool>("IsActive")
            .HasColumnType("bit");

        b.Property<bool>("IsOriginalAvailable")
            .HasColumnType("bit");

        b.Property<bool>("IsPrintAvailable")
            .HasColumnType("bit");

        b.Property<string>("Name")
            .HasColumnType("nvarchar(max)");

        b.HasKey("PaintingId");

        b.ToTable("Painting");
    });

您的问题是您在获取实体时使用了 AsNoTracking,因此上下文不再跟踪更改。因此,您需要在保存之前附加它或删除 AsNoTracking。

如果您不想附加实体,您需要将 GetPaintingByIdAsync 更改为:

public async Task<Painting> GetPaintingByIdAsync(int paintingId)
{
    return await context.Painting
        .Include(x => x.PaintingCategories)
        .ThenInclude(c => c.Category)
        .Where(x => x.PaintingId == paintingId)
        .FirstOrDefaultAsync();
}

如果您想保留 AsNoTracking,那么您需要在 UpdatePainting 中添加:

context.Painting.Update(existingPainting);

在调用保存之前。

更新方法执行以下操作:

Begins tracking the given entity in the Modified state such that it will be updated in the database when SaveChanges() is called.

所以把你的方法改成这样:

public async Task<Painting> UpdatePainting(int paintingId, Painting request)
        {
            var existingPainting = await GetPaintingByIdAsync(paintingId);

            if (existingPainting != null)
            {
                existingPainting.Name = request.Name;
                existingPainting.Description = request.Description;
                existingPainting.ImageUrl = request.ImageUrl;
                existingPainting.IsOriginalAvailable = request.IsOriginalAvailable;
                existingPainting.IsPrintAvailable = request.IsPrintAvailable;
                existingPainting.IsActive = request.IsActive;

                context.Painting.Update(existingPainting);

                await context.SaveChangesAsync();
                return existingPainting;
            }

            return null;
        }

我认为使用 AsNoTracking() 是一个很好的做法,您应该尽可能使用它,但是在 Update 的情况下,您需要通过此 EF 将实体附加到上下文知道这个实体应该更新。

因此,为了解决您的问题,只需在代码中添加一行,如下所示:

//other lines

context.Attach(existingPainting); //<--- by this line you tell EF to track the entity
context.Painting.Update(existingPainting);
await context.SaveChangesAsync();