所以我的数据库中有两个表,联系人和地址:
通讯录:ContactID |地址ID | FirstName |名字
地址:地址ID |地址1 |地址2 |城市|国家|邮政编码
我有一个页面,您可以在其中添加联系人。它包含联系人的所有信息和联系人的地址。这是我提交表单时的代码:
[HttpPost]
public ActionResult Edit(ContactsViewModel viewModel)
{
//if editing an contact, fetch it; otherwise, create a new one
Contact contact = viewModel.ContactId == 0
? new Contact()
: _adminRepository.GetContact(viewModel.ContactId);
TryUpdateModel(contact);
if (ModelState.IsValid)
{
_adminRepository.SaveAddress(contact.Address);
_adminRepository.SaveContact(contact);
return RedirectToAction("Index");
}
return View(viewModel); // validation error, so redisplay same view
}
现在我主要担心的是地址添加成功,但是当我尝试保存联系人时会发生错误,而地址在数据库中没有联系。
如果发生错误,回滚任何更改的最佳做法是什么?
答案 0 :(得分:4)
那应该是一种方法,而不是两种。
如果地址始终与联系人相关(似乎就是这样),那么您应该只有一个存储库 - 例如 ContactRepository
每个聚合根应该有一个存储库,或者简单来说 - 每个实体的存储库都需要自己检索。
我不知道_adminRepository
是什么,但我认为你只是拥有SaveContact(contact)
方法。
您是否正在使用类似于Entity Framework的ORM?如果是这样,两个插入都将在一个事务中完成(由EF处理),因此如果一个失败,两个都将失败。
如果您开始针对多个存储库/聚合根进行更改,那么您将需要类似工作单元或 TransactionScope。
所以听起来你需要重新考虑一下你的存储库设计。对于单个聚合实体(联系人)应该有一个通用的保存方法,而不是每个关系的单独聚合实体。
答案 1 :(得分:1)
“工作单元”模式很好,也可以接受多种操作的解决方案 - 对于db -or anothers操作也是如此 - 请阅读Faisal Mohamood, Program Manager, Entity Framework blogs.中的样本
答案 2 :(得分:0)
您需要在存储库中使用TransactionScope()。查看MSDN forum entry。第一个回复显示了将其集成到方法中的简单示例。关键是如果没有它,就没有办法专门回滚更改。
答案 3 :(得分:0)
我的偏好是使一个存储过程插入两个记录。您可以使用TSQL事务。使用TransactionScope()也可以工作,因此决策应该基于您的数据访问层。如果您已经使用了很多SPROC,请使用事务进行复杂的SPROC。
如果您正在使用Entity Framework(......痛苦!!!!),那么.net TransactionScope()会更好。