给定使用Entity Framework Core和SQL数据库的ASP.NET Core Web应用程序。
尝试更新数据库中的实体时,绝对简单的操作将引发此异常。首先被生产中的错误报告所注意到。
[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");
}
在行上抛出异常:
_context.Update(model.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; }
}
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);
}
}
最佳答案
请改用以下内容:
var group = _context.Group.First(g => g.Id == model.Group.Id);
_context.Entry(group).CurrentValues.SetValues(model.Group);
await _context.SaveChangesAsync();
异常可能是由许多不同的情况引起的,但事实是,您试图更改已被不同标记的对象的状态。
例如,这将产生相同的异常:
var group = new Group() { Id = model.Id, ... };
db.Update(group);
否则,您可能已经分离了N层子级,这就是所有可能。
这样可以确保您只是覆盖现有实体的值。