Mar*_*abo 3 c# entity-framework entity-framework-core asp.net-core-mvc asp.net-core
给定使用Entity Framework Core和SQL数据库的ASP.NET Core webapp.
尝试更新数据库中的实体时,一个绝对简单的操作就是抛出此异常.首先注意到生产中的错误报告.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, [Bind("Group")] EditViewModel model)
{
if (id != model.Group.Id) return NotFound();
if (!ModelState.IsValid) return View(model);
_context.Update(model.Group);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
Run Code Online (Sandbox Code Playgroud)
该行被抛出异常: _context.Update(model.Group);
InvalidOperationException:无法跟踪实体类型"Group"的实例,因为已经跟踪了具有相同键的此类型的另一个实例.添加新实体时,对于大多数键类型,如果未设置任何键,则将创建唯一的临时键值(即,如果为键属性指定了其类型的默认值).如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突.附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文.
显然,没有其他实例.当我在该行上使用断点停止代码并展开_context.Group对象的Results属性时,我能够在我的开发环境中重现异常:
可以理解的是,在扩展结果时,它会加载需要更新的实例,这就是抛出异常的原因.但是部署的生产环境又是什么呢?
谢谢您的帮助!
UPDATE1 Group型号:
public class Group
{
[Display(Name = "ID")]
public string Id { get; set; }
public virtual Country Country { get; set; }
[Required]
[Display(Name = "Country")]
[ForeignKey("Country")]
public string CountryCode { get; set; }
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
UPDATE2基于@Mithgroth的回答,我能够在_context.Update()每次使用时覆盖函数以不需要try-catch:
public interface IEntity
{
string Id { get; }
}
public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
{
if (entity == null)
{
throw new System.ArgumentNullException(nameof(entity));
}
try
{
return base.Update(entity);
}
catch (System.InvalidOperationException)
{
var originalEntity = Find(entity.GetType(), ((IEntity)entity).Id);
Entry(originalEntity).CurrentValues.SetValues(entity);
return Entry((TEntity)originalEntity);
}
}
Run Code Online (Sandbox Code Playgroud)
请改用以下内容:
var group = _context.Group.First(g => g.Id == model.Group.Id);
_context.Entry(group).CurrentValues.SetValues(model.Group);
await _context.SaveChangesAsync();
Run Code Online (Sandbox Code Playgroud)
异常可能是由许多不同的场景引起的,但问题是,您正在尝试更改已标记为不同的对象的状态.
例如,这会产生相同的异常:
var group = new Group() { Id = model.Id, ... };
db.Update(group);
Run Code Online (Sandbox Code Playgroud)
或者你可能已经分离了N层儿童,这一切都是可能的.
这可确保您只是覆盖现有实体的值.
| 归档时间: |
|
| 查看次数: |
9053 次 |
| 最近记录: |