c# - 为 C# 父/子对象构建 SQL 插入事务
问题描述
我正在用 C# 开发一些商业软件对象。每个对象都有能力将自己保存到这样的关联数据库中(每个对象):
public void Save()
{
//Collect object attributes and convert to SQLParameters
//Add SQL Parameters to SQL command and BeginTrans
//Execute, if No Errors, commit, otherwise rollback
}
我已经开始实现继承/父子部分,但我不知道如何使用内部子对象构造父对象 Save() 函数,因为:
- 每个子对象都有自己的 Save() 方法,并带有完整的关联连接、SQL 命令、BeginTrans、参数逻辑和回滚逻辑等。
- 每个 Object.Save() 调用都是该对象/数据库类型的特定存储过程。
- 最重要的是:如果任何子对象保存失败,我希望整个保存回滚。
例如:
如果对象“Customer”有子对象“CustomerInfo”、“Account”和“Dependents”。
执行 Customer.Save 时,如果子对象“CustomerInfo”和“Account”的保存成功,但子对象“Dependents 的保存失败”,那么我希望之前的保存回滚到调用客户父对象。
做这个的最好方式是什么?
我想将保存(参数格式化、执行和回滚)的逻辑封装在每个对象中,即
像这样:
public void ParentSave()
{
Begin Transaction
Try
{
//For each CHILD Object
//ChildObject.Save()
}
Catch(Save Fail)
{
//Rollback all executed saves/transaction(s)
}
IF(Success)
{
//Save parent
Commit parent/overall transaction
}
}
我知道我可以使用“事务”范围,但我不确定如何构建它,或者我是否应该有“嵌套”事务范围。我以前从未使用过事务范围。我知道 Transaction 适用于嵌套的 Begin/Commit 事务(真正的提交只有在 begin trans 计数变为 1 时才会发生),但它是否适用于使用其 Connection/SQLCommand 对象的嵌套事务?
关于“事务范围”:如果每个对象都保存在它自己的封装函数中(每个对象的 save() 启动它自己的连接、SQL 命令、开始/提交、执行和关闭 SQL 命令对象)**
我不想为每个父/子模式编写一个特定的存储过程(即为每个父/子对象的变体都有一个存储过程)。
如果它是必要的,我可以为每个对象编写逻辑来检索它自己的 SQLParameters/命令信息,以便父调用者可以合并它们并在一个大的分阶段事务中执行它们,但我宁愿不这样做。
如果我必须编写分阶段事务,我应该使用“Sql SavePoints”吗?为什么/为什么不?我猜不,好像有任何错误,我正在回滚整个事情。
如果需要“链接”链接这些父对象保存,我可以传递一个连接对象。
解决方案
I would overload Save
and make it a function:
public bool Save()
{
//Open SqlConnection
//Begin Transaction
bool success = Save(cn, Trans);
if (success)
{
//Commit
return true;
}
else
{
//Rollback
return false;
}
}
public bool Save(SqlConnection cn, SqlTransaction trans)
{
//Save self using cn and trans. If fails, immediately return false.
//Save each child using Save(cn, trans). If any one fails, immediately return false.
//If no failures, return true.
}
When you want to save an object, call Save()
(no arguments).
Save()
will create a new connection and transaction and then call Save(SqlConnection cn, SqlTransaction trans)
which will attempt to save the object using the connection and transaction just created. Save(SqlConnection cn, SqlTransaction trans)
will then recursively call itself on all child objects until everything is saved from the top down.
If anything fails at any point, Save(SqlConnection cn, SqlTransaction trans)
will return false
all the way back up the call stack to the initial Save()
which will initiate the rollback. If there are no failures, it will return true
which will trigger the commit.
推荐阅读
- heroku - 如何实现 RQ worker 到 redis 的心跳?
- javascript - 从 html 字符串中删除样式
- bash - 不清楚 curl 选项 -o
. '#' 到底是做什么的? - javascript - 无法在 React.FC 中使用 UseEffect 设置状态
- node.js - 如何通过 nodejs 的 Google Docs API 提供 pdf 文件(不保存文件)?
- php - 将文本与变量中的变量连接起来?
- javascript - 如何仅使用纯 JavaScript 对滚动元素进行简单的不透明度更改?
- azure - 无法将 yaml 部署到 Azure 中的 Kubernetes 集群
- r - 使工具提示出现在绘图对象中不同 ggplot2 方面的对应点上
- pyspark-sql - 每月频率的 Pyspark 性能低下