一次在多个表中插入/更新数据的最佳实践
Posted
技术标签:
【中文标题】一次在多个表中插入/更新数据的最佳实践【英文标题】:Best practice for inserting/updating data in multiple tables at once 【发布时间】:2011-06-25 07:34:30 【问题描述】:所以我的数据库中有两个表,联系人和地址:
联系人:ContactID |地址ID |名字 |姓氏
地址:地址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
现在我主要关心的是地址添加成功,但是当我尝试保存联系人时出现错误,使地址在数据库中没有联系人。
如果发生错误,回滚任何更改的最佳做法是什么?
【问题讨论】:
你在 SaveAddress 和 SaveContact 中做什么?你尝试提交给数据库吗?尝试使用工作单元 【参考方案1】:那应该是一种方法,而不是两种。
如果一个 Address 总是与一个 Contact 相关联(看起来是这样),那么您应该只有一个存储库 - 例如一个 ContactRepository.
您应该为每个聚合根创建一个存储库,或者简单地说 - 每个需要自行检索的实体都有一个存储库。
我不知道_adminRepository
是什么,但我认为你只是有一个SaveContact(contact)
方法。
您使用的是像实体框架这样的 ORM 吗?如果是这样,两个插入都将在一个事务中完成(由 EF 处理),所以如果一个失败,两个都会失败。
如果您开始对多个存储库/聚合根进行更改,那么您将需要工作单元或TransactionScope。
所以听起来您需要重新考虑一下您的存储库设计。单个聚合实体(联系人)应该有一个通用的 Save 方法,而不是每个关系的单独方法。
【讨论】:
是的,我正在使用实体框架。我的管理存储库包含每个实体的函数,因此有 SaveContact()、SaveAddress、GetAllContacts()、GetAllAddresses() 等。我这样做对吗? @Steven - 两个问题:1)你可以添加一个没有联系人的地址吗? 2) 你可以添加没有地址的联系人吗?听起来答案是否定的。对吗? 实际上是和不是:)。您可以添加没有联系人的地址,但您必须添加有地址的联系人。 是的,ContactRepository 似乎是 transactionscope 的更好名称 +1 @Steven - 对,那么它归结为您是否需要独立访问联系人和地址(例如通过 ID)。如果这样做,那么您将需要 2 个存储库。【参考方案2】:“工作单元”模式很好并被接受,用于 db 上的多个操作 - 或其他操作 - 请阅读来自 Faisal Mohamood, Program Manager, Entity Framework blogs. 的示例
【讨论】:
【参考方案3】:您需要在存储库中使用 TransactionScope()。查看MSDN forum entry。第一个回复显示了一个将其集成到方法中的简单示例。关键是没有它就没有办法专门回滚更改。
【讨论】:
【参考方案4】:我的偏好是创建一个存储过程来插入两条记录。您可以使用 TSQL 事务。使用 TransactionScope() 也可以,因此决定可能应该基于您的数据访问层。如果您已经在使用很多 SPROC,请使用事务制作一个复杂的 SPROC。
如果您使用的是实体框架(......痛苦!!!!)那么 .net TransactionScope() 会更好。
【讨论】:
我正在使用简单的 dapper 进行数据操作,并希望使用普通的 sql 查询(无存储过程)来实现。如果我采用第二种方法,我必须为我的数据库中的每个实体创建存储库,其中代码可能更多,而且我需要对所有存储库进行单元测试。以上是关于一次在多个表中插入/更新数据的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章