无法捕获DbUpdateConcurrencyException

时间:2019-07-13 18:36:05

标签: c# asp.net entity-framework optimistic-concurrency

我正在尝试Catch DbUpdateConcurrencyException

在调试时,我得到了entity.RowVersion与productEdit.RowVersion不同。

但是我不知道为什么该程序可以成功保存数据。

public async Task<IActionResult> Patch(Guid id, [FromBody] ProductEditModel productEdit)
{
    var entity = await this.unitOfWork.Products.GetByIdAsync(id);

    this.mapper.Map(productEdit, entity);

    try
    {
        await this.unitOfWork.SaveAsync();   // <<---  here.
    }
    catch (DbUpdateConcurrencyException ex)
    {
        return Conflict(ex);
    }

    return Ok();
}

这是我的实体类:

public abstract class BaseEntity
{
    [Key, Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }
}

public class Product : BaseEntity
{
    public String Name { get; set; }
    public String Description { get; set; }
    public double Price { get; set; }
}

1 个答案:

答案 0 :(得分:1)

here描述了类似的问题。它是关于EF核心的,但是我也已经对其进行EF6测试,并且在那里也一样。

最重要的是,EF将RowVersion属性的原始值与当前数据库值进行比较。此比较是SQL update命令的一部分,该命令包含一个WHERE子句:

UPDATE ...
WHERE [ID] = @p1 AND [RowVersion] = @p2;

@p2参数是RowVersion属性的原始值。如果版本不匹配,则会抛出DbUpdateConcurrencyException

所以这里有问题...

this.mapper.Map(productEdit,entity);

...仅更新RowVersion的当前值。

因此如果您要操纵RowVersion的值,则必须更改原始值。为此,您需要实体条目,如下所示:

context.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowversion;

由于您将上下文包装在工作单元/存储库模式中,因此必须了解如何实现此目的。

但是,您可能需要考虑其他方法。我认为您不应该从数据库中获取Product实体并设置其值并操纵其RowVersion。将productEdit映射到新的Product实体对象,然后将该对象附加到上下文中更为合适。这会将RowVersion的原始值自动设置为您想要的版本。作为奖励,它节省了往返数据库的时间。