【发布时间】:2016-12-26 14:24:30
【问题描述】:
我将 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 并带有此消息:
附加信息:无法跟踪实体类型“用户”的实例,因为已经在跟踪具有相同键的该类型的另一个实例。添加新实体时,对于大多数键类型,如果没有设置键(即,如果键属性为其类型分配了默认值),则会创建一个唯一的临时键值。如果您为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。
【问题讨论】:
-
似乎在同一上下文中的某处您正在获取相同的实体。
-
但是在这种情况下,
if语句中的条件应该返回 false,因为实体已经被提取并且在上下文中可用,对吧?if可以防止这种可能性,我不明白为什么它没有按预期工作。 -
你不直接使用
DbContext.Update有什么原因吗? -
“仍然执行在 if 语句中” – 你确定错误是由你正在调试的那一行引起的吗?也许
Update方法也是从另一个地方调用的?你检查了完整的堆栈跟踪吗? -
@poke,我尝试了
DbContext中的Update方法,但它仍然发出同样的错误。我添加了一个带有完整错误消息的编辑
标签: c# entity-framework asp.net-core .net-core entity-framework-core