当前位置: 首页 > 知识库问答 >
问题:

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

甄德寿
2023-03-14

我的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; }
}

要在其中向数据库中添加新赌注实体的代码:

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:我的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方法时,代码会引发以下异常:

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

我正在尝试使用

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

但代码仍然会抛出一个错误。

共有1个答案

宓诚
2023-03-14

这是导致问题的代码:

  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;
 类似资料:
  • 让我快速描述一下我的问题。 我有5个客户的5个数据库,每个数据库都有一个名为SubnetSettings的表。 我已经创建了一个下拉列表来选择一个客户,并将显示属于所选客户的SubnetSSet表,并允许我创建、编辑和删除。 我可以毫无问题地创建、删除,但当我想编辑数据时,它会带来错误: /运输管理系统应用程序中的服务器错误。 附加“CFS”类型的实体。领域实体。SubnetSettings“失败

  • 错误消息:附加类型的实体失败,因为相同类型的另一个实体已具有相同的主键值。 问题:我如何以类似于下面代码中AttachActivity方法所示的方式附加实体? 我必须假设上面错误消息的“另一个实体”部分指的是内存中存在但超出范围的对象(?)。我之所以注意到这一点,是因为我尝试附加的实体类型的DBSet的本地属性返回零。 我有理由相信实体不存在于上下文中,因为我遍历代码并在创建上下文时观察上下文。实

  • 错误消息: 正在附加“FaridCRMData”类型的实体。模型。“Customer”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的 我的代码: FactorService. BaseService.cs:

  • 我在代码中偶然发现了一个奇怪的bug。以前是有效的,但现在有时也有效。 我正在使用EF6编辑具有某些关系的实体。为了不编辑关系,我“附加”了它们(参见示例代码)。 我编辑了这些名字以保持简单。 以下行 抛出此错误: 附加类型为“C”的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“Unchanged”或“Mo

  • 简而言之,在发布包装器模型并将一个条目的状态更改为“已修改”期间引发异常。更改状态之前,状态设置为“已分离”,但调用Attach()会引发相同的错误。我正在使用EF6。 请在下面找到我的代码(型号名称已更改以便于阅读) 模型 控制器 如上图所示 引发异常: 附加类型为“A”的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实

  • 我正在使用automapper重构一些代码,请参见下面注释掉的旧代码。 编辑:请注意,属性对象是从基础设置的,因此建议的重复问题不适用。 当状态设置为modified时,我得到以下异常:; 附加“M.Survey”类型的实体。ServiceLayer。模型属性“”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“U