附加类型''的实体失败,因为另一个实体具有相同的主键值

时间:2017-04-27 17:35:18

标签: c# entity-framework asp.net-web-api entity-framework-5

我的WebApi应用程序有一个小问题。 当我将新实体添加到我的数据库中时会发生此问题。

实体:

public sealed class Lot : Entity
{
    [Required, DefaultValue(false)]
    public bool IsActive { get; set; }

    [Required, DefaultValue(false)]
    public bool IsDelete { get; set; }

    [Required, DefaultValue(false)]
    public bool InCredit { get; set; }

    [DefaultValue(1), Range(1, 10)]
    public int PhaseNumber { get; set; }

    [Required]
    public decimal DesiredPrice { get; set; }

    public Guid? AcceptedBetId { get; set; }

    [Required]
    public DateTime CreationDate { get; set; }

    public DateTime ExpirationDateTime { get; set; }

    [Required]
    public string City { get; set; }

    public User User { get; set; }

    public Car Car { get; set; }

    public ICollection<Bet> Bets { get; set; }

    public Lot()
    {
        Bets = new List<Bet>();
    }
}

public sealed class Bet : Entity
{
    [Required, Range(0.0, double.MaxValue)]
    public decimal Price { get; set; }

    [Required]
    public DateTime CreationDate { get; set; }

    [Range(0, int.MaxValue)]
    public int BetNumber { get; set; }

    public Lot Lot { get; set; }

    public User User { get; set; }
}

我想在我的数据库中添加新Bet实体的代码:

Lot lot;
using (LotsManager lotsManager = new LotsManager())
{
     lot = await lotsManager.GetLotAsync(model.LotId);
}

User user;
using (UserManager userManager = new UserManager())
{
      user = await userManager.GetUserAsync(model.UserInfoId);
}

var bet = new Bet
{
      Id = Guid.NewGuid(),
      Price = model.Price,
      CreationDate = DateTime.Now,
      BetNumber = lastBetNumber + 1,
      Lot = lot,
      User = user
 };

 await _betsManager.SaveBetAsync(bet);

在这个地方将我的实体添加到DB(db:my SQL)

protected async Task Save<T>(T entity) where T : Entity
    {
        using (var dbContextTransaction = _context.Database.BeginTransaction())
        {
            try
            {
                var dbEntity = await _context.Set<T>().SingleOrDefaultAsync(x => x.Id == entity.Id);

                _context.Set<T>().Attach(entity);
                _context.Entry(entity).State = dbEntity != null ? EntityState.Modified : EntityState.Added;

                await _context.SaveChangesAsync();
                dbContextTransaction?.Commit();
            }
            catch (DbEntityValidationException ex)
            {
                dbContextTransaction?.Rollback();

                var error = ex.EntityValidationErrors.First().ValidationErrors.First();
                throw new InvalidModelException(error.ErrorMessage);
            }
            catch (Exception ex)
            {
                dbContextTransaction?.Rollback();

                throw new InvalidDbOperationException(ex.Message);
            }
        }
    }

当我调用我的save方法时,我的代码抛出了这个异常:

  

附加类型&#39; WebCar.Domain.Entities.Lot&#39;的实体。失败,因为同一类型的另一个实体已具有相同的主键值。使用&#39;附加&#39;方法或将实体的状态设置为“未更改”#39;或者&#39;修改&#39;如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者&#39;修改&#39;酌情。

我尝试使用

_context.Set<T>().Attach(entity);
_context.Entry(entity).State = EntityState.Unchanged;
or
_context.Entry(entity).State = EntityState.Unchanged;

但是代码仍然会出错。

1 个答案:

答案 0 :(得分:0)

这是导致问题的代码:

  var dbEntity = await _context.Set<T>().SingleOrDefaultAsync(x => x.Id == entity.Id);
  _context.Set<T>().Attach(entity);

在这种情况下,如果您找到现有实体,它就会存储在上下文中。如果您尝试添加已存在的EF,则无法处理。有几种方法可以解决这个问题。我将展示两个:

 var dbEntity = await _context.Set<T>().AsNoTracking().SingleOrDefaultAsync(x => x.Id == entity.Id);

理论上,如果你不跟踪它,那么你应该能够添加另一个。

但是,我觉得这种方式更好:

bool doesEntityExist = await _context.Set<T>().Any(x => x.Id == entity.Id);
_context.Set<T>().Attach(entity);
_context.Entry(entity).State = doesEntityExist ? EntityState.Modified : EntityState.Added;