Dispose() 如何知道它是由于异常而被调用的?
我想编写一个简单的工作单元类,其行为如下:
using (var unitOfWork = new UnitOfWork())
{
// Call the data access module and don't worry about transactions.
// Let the Unit of Work open a session, begin a transaction and then commit it.
}
这就是我到目前为止所拥有的(如果您认为我的设计错误,欢迎任何评论):
class UnitOfWork : IDisposable
{
ISession _session;
ITransation _transaction;
.
.
.
void Dispose()
{
_transaction.Commit();
_session.Dispose();
}
}
我想做的是回滚事务以防数据访问代码抛出一些异常。所以 Dispose()
方法看起来像这样:
void Dispose()
{
if (Dispose was called because an exception was thrown)
{
_transaction.Commit();
}
else
{
_transaction.RollBack();
}
_session.Dispose();
}
这有意义吗?如果可以的话,该怎么办呢?
I'd like to write a simple unit of work class that would behave like this:
using (var unitOfWork = new UnitOfWork())
{
// Call the data access module and don't worry about transactions.
// Let the Unit of Work open a session, begin a transaction and then commit it.
}
This is what I have so far (any comments will be welcome if you think my design is wrong):
class UnitOfWork : IDisposable
{
ISession _session;
ITransation _transaction;
.
.
.
void Dispose()
{
_transaction.Commit();
_session.Dispose();
}
}
What I would like to do is to roll back the transaction in case the data acess code threw some exception. So the Dispose()
method would look something like:
void Dispose()
{
if (Dispose was called because an exception was thrown)
{
_transaction.Commit();
}
else
{
_transaction.RollBack();
}
_session.Dispose();
}
Does it make sense? And if so, how can it be done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
“Dispose()”应该与事务提交或回滚无关。您应该在 Dispose() 方法中处置您的事务。从长远来看,更改 Dispose() 方法的语义只会给您和使用您的类的其他人增加混乱。
Transaction 的 Commit() 和 RollBack() 方法与 Dispose() 方法没有任何关系,因为这两个方法和 Dispose() 之间没有相关性,因为无论最终结果是什么,您都必须处理事务。
对于连接和事务来说,这是正确使用的模式。请注意,Roolback(0 涉及异常(而不是 dispose)),
因此请使用 Commit()、Roolback() 和 Dispose() 方法在 UnitOfWork 中模仿此模式。
The "Dispose()" should have nothing to do with transaction commit or rollback. You should dispose you transaction in your Dispose() method. Changing the semantics of your Dispose() method will only add to confusion in the long run for you and anyone else using your class.
The Transaction's Commit() and RollBack() methods have nothing whatsoever to do with a Dispose() method since there is no correlation between these two method and Dispose(), since you have to dispose a transaction no matter what the final outcome is.
This is the correct pattern to use as regards connections and transactions. Notice that Roolback(0 relates to an exception (and not dispose)
So mimic this pattern in your UnitOfWork, with methods for Commit(), Roolback() and Dispose().
这里的游戏有点晚了,但请检查 Ayende 的这篇文章提供了一个(有点疯狂的)解决方案:
在 Dispose 方法中,您只需要弄清楚它是否“干净”地到达那里 - 即图如果在提交事务之前存在未处理的异常,则输出:
A bit late to the game here, but check this post from Ayende for a (slightly mad) solution:
In the Dispose method, you just need to figure out whether or not it got there 'cleanly' - i.e. figure out if an unhandled exception exists before committing the transaction:
Dispose
的要点是它始终运行。通过使用这种提交-回滚习惯用法,您不需要知道其中的区别。在这里我们看到要么抛出异常,要么提交unitOfWork。然后我们可以在
UnitOfWork
中使用 bool 来跟踪 Commit 是否被执行。然后Dispose
可以Rollback不提交。这样,工作单元总是要么回滚,要么提交。无论如何,我会避免将提交放在处置中。对于初学者来说,
ITransaction.Commit
方法通常可能会抛出错误异常 - 这是完全正常的。但是,Dispose
方法不应该抛出异常。请参阅此链接并在 Stackoverflow 上搜索有关的更多深入信息为什么。我正在大笔思考类似的事情
我想说的是,完全忘记调用 Commit 的问题并不是那么大,因为除非提交,否则客户端代码将无法工作,因为事务是
回滚
'ed并且不应用更改,这些更改将在夹具内或手动执行代码时发现。我实际上尝试在一个项目中使用带有 lambda 的语法来处理这个问题,如下所示
这样客户就不需要担心提交任何内容。实际上我最终对此感到后悔,因为它让事情变得太复杂了,并且希望我放弃上述方法。
The point of
Dispose
is that it is always run. And by using this commit-rollback idiom you don't need to know the difference.Here we see that either an exception is thrown or the unitOfWork is committed. We can then have a bool in
UnitOfWork
keeping track whether the Commit was executed or not. Then theDispose
can Rollback not commited. This way the unit-of-work is always either rollbacked or commited.I would in any case avoid having the Commit inside the Dispose. For starters a
ITransaction.Commit
method typically may throw exceptions on errors - This is perfectly normal. However, theDispose
method is not supposed to throw exceptions. See this link and search on Stackoverflow for more indepth information on why.I'm thinking something like this in big strokes
The problem with forgetting to call Commit altogether I would say is not that big since unless commited, the client code will not work since the transaction is
Rollback
'ed and changes are not applied which will be discovered when exercising the code inside a fixture or manually.I actually tried to deal with this in one project by using a syntax with lambdas like so
This way clients did not need to worry about Commiting anything. I actually ended up regretting this since it complicated things too much and wished I hade gone with the above approach.
您需要在
using
块末尾使用UnitOfWork.Commit()
。在UnitOfWork
内部,您有一个comfilled
标志,您可以在UnitOfWork.Dispose
中检查该标志。如果那里的标志为false
,那么您将使用UnitOfWork.Rollback()
。You need to
UnitOfWork.Commit()
at the end of theusing
block. InsideUnitOfWork
you have acommitted
flag that you check inUnitOfWork.Dispose
. If the flag isfalse
there, then youUnitOfWork.Rollback()
.毕竟,我实现了一个方法,所有操作都应该通过该方法执行:
After all, I implemented a method through which all operations should be performed: