这是一个EF Core错误还是我做错了更新一个实体?

时间:2016-12-26 14:24:31

标签: c# entity-framework asp.net-core .net-core entity-framework-core

我将Entity Framework Core与存储库模式结合使用。为了帮助我,我使用基本的CRUD方法编写了一个基本存储库。更新方法如下:

public void Update(TEntity entity)
{
    var contextEntry = _context.Entry<TEntity>(entity);
    if (contextEntry.State == EntityState.Dettached)
    {
        _context.Attach(entity);
    }
    contextEntry.State = EntityState.Modified;
    _context.SaveChanges();
}

鉴于包含此方法的BaseRepository类,我创建了一个继承自此

User存储库
public class UserRepository : BaseRepository<User>, IUserRepository
{
}

我在使用ASP.NET Core编码的一个Web API的PUT方法中使用了它

[HttpPut("~/api/users/{id}")]
public IActionResult Put(int id, [FromBody] User user)
{
    if (user == null || user.UserId != id)
    {
        return BadRequest();
    }

    userRepository.Update(user);
    return new NoContentResult();
}

现在,在发出请求时,我在_context.Attach(entity)行中收到一个错误。例外情况是它无法添加实体进行跟踪,因为已经有另一个实体跟踪了相同的密钥。

调试时,我看到contextEntry.State设置为Unchanged。因此,显然不等于EntityState.Dettached。仍然,执行进入if语句并尝试附加实体。

这里有些不对劲。这是一个错误吗?或者我做错了什么?我相信我是这个更新策略做错事的人,但我不确定。在那种情况下,我的方法出了什么问题?

编辑:我更新了Update方法,仅使用_context.Update(entity)_context.SaveChanges()之后。尽管如此,_context.Update(entity)仍会使用以下消息抛出一个InvalidOperationException

  

附加信息:实体类型的实例&#39;用户&#39;无法跟踪,因为已经跟踪了具有相同密钥的此类型的另一个实例。添加新实体时,对于大多数密钥类型,如果未设置密钥,则将创建唯一的临时密钥值(即,如果为密钥属性指定了其类型的默认值)。如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。

2 个答案:

答案 0 :(得分:0)

您从数据库中获取了相同的实体,在项目中的某些位置,这就是为什么它会给您带来错误。

IsExpanded方法中,您只需在上下文中添加实体即可获得ItemsSource不变的原因。

您可以通过两种方式解决此问题。

  1. 当您从数据库获取时,需要在同一实体上调用Update方法。

  2. 将您在contextEntry.State方法中收到的实体的值复制到现有的上下文实体,并将该实体保存在数据库中。

答案 1 :(得分:0)

所有信息都在异常消息中......您已经拥有附加了该主键的实体的另一个副本。

我会推荐以下之一(首选首选):

  1. 为每个操作使用新的上下文,没有长期存储库/上下文
  2. 使用主键在您的上下文中使用.Set<TEntity>.Find(object[] key),以便检索您已有的任何实体。
  3. 在您当前的更新方法中,使用Set<TEntity>.Local.Find(..)检查它是否已存在