c# - 存储库模式和 TransactionScope
问题描述
考虑具有 OrderItem 集合的 Order(聚合根)实体。
class Order
{
public string Number;
public List<OrderItem> OrderItems;
}
class OrderItem
{
public string Name;
public float Price;
}
然后 OrderRepository 像这样:
class OrderRepository
{
IDbConnection connection;
void SaveOrder(Order o)
{
connection.Execute("INSERT INTO Order ...");
foreach(var oi in o.OrderItems)
{
connection.Execute("INSERT INTO OrderItem ...");
}
}
}
问题是 TransactionScope 是否应该放在 OrderRepository 中。像这样的东西:
class OrderRepository
{
IDbConnection connection;
void SaveOrder(Order o)
{
using(var scope = new TransactionScope())
{
connection.Execute("INSERT INTO Order ...");
foreach(var oi in o.OrderItems)
{
connection.Execute("INSERT INTO OrderItem ...");
}
scope.Complete();
}
}
}
我对此的考虑:我们需要确保调用保存后数据是一致的。这意味着如果没有任何 TransactionScope,无论是在存储库内部还是外部,这可能会导致一些 OrderItems 被提交,而另一些则没有(异常)。然后我们可以有:
- TransactionScope 仅在存储库之外。包装多个存储库调用。
using(var scope = new TransactionScope())
{
orderRepository.Save(order);
warehouseRepository.Save(...);
}
- TransactionScope 在 1) 外部和存储库内部(见上文)。
我在 1) 中看到的问题是 OrderRepository 需要假设调用代码将提供 TransactionScope。否则,它不能保证 Order 聚合的一致持久性。
解决方案
存储库可以假设自己在更高级别(即用例)发起的事务的上下文中运行。此外,它根本不应该关心它可能运行或可能不运行的上下文。
因此,不建议在存储库中启动事务。
您可能希望为组成单个聚合的多个实体拥有多个存储库对象,这意味着它们都必须在单个事务下运行。事务本质上是一个工作单元,一个工作单元是一个抽象,应该出现在应用层中。
推荐阅读
- r - 如何使用 parse_date_time() 将我的日期变量转换为不同的日期时间变量?
- c# - 实现动态/级联列表框的最佳方式
- javascript - 如何在 Electron 应用程序中检测系统空闲并执行某些操作
- tileserver-gl - 如何确定缩放高度以从 WMTS 服务器请求平铺
- android - 我在编译 mediapipe 时出现以下错误
- c# - 如何编写 Roslyn 代码分析器以防止不良日志记录做法
- sql - 当另一列具有匹配值时,选择一列中具有最大值的行
- java - 静态嵌套类的实例变量与外部类的静态变量
- ios - 是否可以在没有apple pay接口的情况下进行apple pay支付?
- r - 如何创建由包含相应行中其他值的列表组成的数据框列(在 R 中)?