我有一个非常简单的模型:
public class Item : DbEntity
{
public string Name {get;set;}
public int Quantity {get;set;}
public virtual Category Category {get;set;}
}
public class Category : DbEntity
{
public string Name {get;set;}
}
我使用以下方法保存并提交对数据库的更改:
public void SaveEntity<TEntity>(TEntity entity) where TEntity : DbEntity
{
if (entity.Id.Equals(Guid.Empty))
_context.Set<TEntity>().Add(entity);
else
_context.Entry(entity).State = System.Data.EntityState.Modified;
_context.SaveChanges();
}
public void DeleteEntity<TEntity>(TEntity entity) where TEntity : DbEntity
{
_context.Set<TEntity>().Remove(entity);
_context.SaveChanges();
}
这些保存和删除方法驻留在Repository中,此Repository是Ninjected,因此它应该在整个应用程序生命周期中具有一个常量状态。这是一种久经考验的方法,它一直对我有用。现在我出于某种原因这样做了:
[HttpPost]
public ActionResult Edit(MenuItemViewModel vm)
{
if (ModelState.IsValid)
{
// TODO: Add ViewModel Logic
vm.MenuItem.Category = _repository.Categories.FirstOrDefault(x => x.Id.Equals(vm.SelectedCategory));
try
{
// TODO: Add Save Logic
_repository.SaveEntity(vm.MenuItem);
TempData["success"] = true;
TempData["message"] = String.Format("Saved {0} Successfully", vm.MenuItem.Description);
}
catch (Exception ex)
{
TempData["error"] = true;
TempData["message"] = "Error Occured";
}
return _redirectTo;
}
return View("Shape", vm);
}
视图部分很简单,只有Name
和Quantity
的一些字段,Category
是一个Drop Down
框,其中包含所有类别名称{{1} }和id为Text
,这将被发送回存储库所在的服务器并收集新的Value
并将其分配给实体。
由于某种原因,这只是没有对数据库进行任何更改,前后断点,当我在检查数据库后断开时,它没有改变!
任何人都可以看到阻止它更新的愚蠢的小错误。
修改
请阅读此StackOverflow Post,我选择了所说的部分,然后先将其附加然后进行编辑,因为调用附加时,您将其称为Category
状态,然后当您修改它,当您拨打Unchanged
时,将保存更改。
这与它有什么关系吗?!
更新
好的一些有趣的消息,我逐步完成了SaveChanges()
方法,在我再次检查上传SaveEntity
之后,我再次检查了上下文,它显示它已经更新了?!我重定向到另一个控制器和操作的事实是否会影响结果或表格修改?我认为问题不在于SaveChanges()
方法!!
最新更新
我更改了SaveEntity
的模型,只需添加行Item
,只需更改public Guid CategoryId {get;set;}
即可启用Category
。现在,当我尝试Cascade On Delete
:
发生了引用完整性约束违规:定义引用约束的属性值在关系中的主体和从属对象之间不一致。
答案 0 :(得分:1)
所以,为了解决这个问题,我将Item
实体更改为:
public class Item : DbEntity
{
public string Name {get;set;}
public int Quantity {get;set;}
public Guid? CategoryId {get;set;}
public virtual Category Category {get;set;}
}
这基本上使得更改Category
更容易,更快捷,因为您不必再次调用数据库。 ?
将此Cascade Delete
设置为可为空的属性,将No Action
设置为Item
,这样当您删除Categories
时,它就不会烦人地删除并删除相关的public Guid? CategoryId {get;set;}
}。
我仍然不知道为什么原始方式不起作用,它在过去已经完成并且它曾经否定必须放置Category_Id
,因为它将设置可为空的属性并且已经创建了{{ 1}}字段。但嘿嘿,这就是它想成为的样子,然后我会打球!!
答案 1 :(得分:0)
在SaveEntity中,如果Id不等于Guid.Empty,则不将该项附加到上下文,仅将State设置为Modified。尝试:
public void SaveEntity<TEntity>(TEntity entity) where TEntity : DbEntity
{
if (entity.Id.Equals(Guid.Empty))
{
_context.Set<TEntity>().Add(entity); // Automatically sets state to Added
}
else
{
_context.Set<TEntity>().Attach(entity);
_context.Entry(entity).State = System.Data.EntityState.Modified;
}
_context.SaveChanges();
}
此外,对于DeleteEntity,请尝试附加和删除:
public void DeleteEntity<TEntity>(TEntity entity) where TEntity : DbEntity
{
_context.Set<TEntity>().Attach(entity); // Attaches entity with state Unchanged
_context.Set<TEntity>().Remove(entity); // Changes entity state to Deleted
_context.SaveChanges();
}
关键是在断开连接的环境(如ASP.NET)中,从帖子返回的模型不会附加到上下文中,因此需要重新附加才能处理它。
作为测试,在调用SaveChanges之前检查现有代码中实体的状态,并且它可能不变,意味着不会对其执行任何操作。