Dispose() 如何知道它是由于异常而被调用的?

发布于 2024-10-21 07:34:38 字数 854 浏览 4 评论 0原文

我想编写一个简单的工作单元类,其行为如下:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夏花。依旧 2024-10-28 07:34:38

“Dispose()”应该与事务提交或回滚无关。您应该在 Dispose() 方法中处置您的事务。从长远来看,更改 Dispose() 方法的语义只会给您和使用您的类的其他人增加混乱。

Transaction 的 Commit() 和 RollBack() 方法与 Dispose() 方法没有任何关系,因为这两个方法和 Dispose() 之间没有相关性,因为无论最终结果是什么,您都必须处理事务。

对于连接和事务来说,这是正确使用的模式。请注意,Roolback(0 涉及异常(而不是 dispose)),

connection.Open();
var trasnaction = null;
try
{
  transaction = connection.BeginTransaction(); 
  ///Do Some work
  transaction.Commit();
}
catch
{
  transaction.Rollback();
}
finally
{
  if (transaction != null)
    transaction.Dispose();
  connection.Close();
}

因此请使用 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)

connection.Open();
var trasnaction = null;
try
{
  transaction = connection.BeginTransaction(); 
  ///Do Some work
  transaction.Commit();
}
catch
{
  transaction.Rollback();
}
finally
{
  if (transaction != null)
    transaction.Dispose();
  connection.Close();
}

So mimic this pattern in your UnitOfWork, with methods for Commit(), Roolback() and Dispose().

甜宝宝 2024-10-28 07:34:38

这里的游戏有点晚了,但请检查 Ayende 的这篇文章提供了一个(有点疯狂的)解决方案:

在 Dispose 方法中,您只需要弄清楚它是否“干净”地到达那里 - 即图如果在提交事务之前存在未处理的异常,则输出:

public class ExceptionDetector : IDisposable
{
    public void Dispose()
    {
        if (Marshal.GetExceptionCode()==0)
            Console.WriteLine("Completed Successfully!");
        else
            Console.WriteLine("Exception!");
    }
}

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:

public class ExceptionDetector : IDisposable
{
    public void Dispose()
    {
        if (Marshal.GetExceptionCode()==0)
            Console.WriteLine("Completed Successfully!");
        else
            Console.WriteLine("Exception!");
    }
}
半仙 2024-10-28 07:34:38

Dispose 的要点是它始终运行。通过使用这种提交-回滚习惯用法,您不需要知道其中的区别。

using (var unitOfWork = new UnitOfWork())
{
    // use unitOfWork here - No need to worry about transactions for this code.
    unitOfWork.Commit();
}

在这里我们看到要么抛出异常,要么提交unitOfWork。然后我们可以在 UnitOfWork 中使用 bool 来跟踪 Commit 是否被执行。然后Dispose可以Rollback不提交。这样,工作单元总是要么回滚,要么提交。

无论如何,我会避免将提交放在处置中。对于初学者来说,ITransaction.Commit 方法通常可能会抛出错误异常 - 这是完全正常的。但是,Dispose 方法不应该抛出异常。请参阅此链接并在 Stackoverflow 上搜索有关的更多深入信息为什么

我正在大笔思考类似的事情

class UnitOfWork : IDisposable
{
   ISession _session;
   ITransation _transaction;
   bool _commitTried;

   // stuff goes here

   void Commit()
   {
      _commitTried = true;
      _transaction.Commit();
   }

   void Dispose()
   {
      if (!_commitTried) _transaction.Rollback();
      _transaction.Dispose();
      _session.Dispose();
   }
}

我想说的是,完全忘记调用 Commit 的问题并不是那么大,因为除非提交,否则客户端代码将无法工作,因为事务是回滚'ed并且不应用更改,这些更改将在夹具内或手动执行代码时发现。

我实际上尝试在一个项目中使用带有 lambda 的语法来处理这个问题,如下所示

_repository.InTransactionDo(ThisMethodIsRunInsideATransaction);

这样客户就不需要担心提交任何内容。实际上我最终对此感到后悔,因为它让事情变得太复杂了,并且希望我放弃上述方法。

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.

using (var unitOfWork = new UnitOfWork())
{
    // use unitOfWork here - No need to worry about transactions for this code.
    unitOfWork.Commit();
}

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 the Dispose 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, the Dispose 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

class UnitOfWork : IDisposable
{
   ISession _session;
   ITransation _transaction;
   bool _commitTried;

   // stuff goes here

   void Commit()
   {
      _commitTried = true;
      _transaction.Commit();
   }

   void Dispose()
   {
      if (!_commitTried) _transaction.Rollback();
      _transaction.Dispose();
      _session.Dispose();
   }
}

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

_repository.InTransactionDo(ThisMethodIsRunInsideATransaction);

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.

神经大条 2024-10-28 07:34:38

您需要在 using 块末尾使用 UnitOfWork.Commit() 。在 UnitOfWork 内部,您有一个 comfilled 标志,您可以在 UnitOfWork.Dispose 中检查该标志。如果那里的标志为false,那么您将使用UnitOfWork.Rollback()

You need to UnitOfWork.Commit() at the end of the using block. Inside UnitOfWork you have a committed flag that you check in UnitOfWork.Dispose. If the flag is false there, then you UnitOfWork.Rollback().

节枝 2024-10-28 07:34:38

毕竟,我实现了一个方法,所有操作都应该通过该方法执行:

class UnitOfWork : IDisposable
{
   ...
   public void DoInTransaction(Action<ISession> method)
   {
       Open session, begin transaction, call method, and then commit. Roll back if there was an exception.
   }
}

After all, I implemented a method through which all operations should be performed:

class UnitOfWork : IDisposable
{
   ...
   public void DoInTransaction(Action<ISession> method)
   {
       Open session, begin transaction, call method, and then commit. Roll back if there was an exception.
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文