我将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;无法跟踪,因为已经跟踪了具有相同密钥的此类型的另一个实例。添加新实体时,对于大多数密钥类型,如果未设置密钥,则将创建唯一的临时密钥值(即,如果为密钥属性指定了其类型的默认值)。如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。
答案 0 :(得分:0)
您从数据库中获取了相同的实体,在项目中的某些位置,这就是为什么它会给您带来错误。
在IsExpanded
方法中,您只需在上下文中添加实体即可获得ItemsSource
不变的原因。
您可以通过两种方式解决此问题。
当您从数据库获取时,需要在同一实体上调用Update
方法。
将您在contextEntry.State
方法中收到的实体的值复制到现有的上下文实体,并将该实体保存在数据库中。
答案 1 :(得分:0)
所有信息都在异常消息中......您已经拥有附加了该主键的实体的另一个副本。
我会推荐以下之一(首选首选):
.Set<TEntity>.Find(object[] key)
,以便检索您已有的任何实体。Set<TEntity>.Local.Find(..)
检查它是否已存在