NHibernate - 分布式事务并提供您自己的连接会导致异常

发布于 2024-10-03 08:14:04 字数 3643 浏览 3 评论 0原文

当参与分布式事务并且您通过指定自己的连接对象打开会话时,NHibernate 会引发异常。

Unhandled Exception: System.InvalidOperationException: Disconnect cannot be call
ed while a transaction is in progress.
   at NHibernate.AdoNet.ConnectionManager.Disconnect()
   at NHibernate.Impl.SessionImpl.Close()
   at NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing)
   at NHibernate.Transaction.AdoNetWithDistrubtedTransactionFactory.<>c__Display
Class1.<EnlistInDistributedTransactionIfNeeded>b__0(Object sender, TransactionEv
entArgs e)
   at System.Transactions.TransactionCompletedEventHandler.Invoke(Object sender,
 TransactionEventArgs e)
   at System.Transactions.TransactionStatePromotedCommitted.EnterState(InternalT
ransaction tx)
   at System.Transactions.InternalTransaction.DistributedTransactionOutcome(Inte
rnalTransaction tx, TransactionStatus status)
   at System.Transactions.Oletx.RealOletxTransaction.FireOutcome(TransactionStat
us statusArg)
   at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(Transact
ionStatus status)
   at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback
(Object state, Boolean timeout)
   at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback
(Object state, Boolean timedOut)

以下代码将重现该问题;参考当前的FluentNibernate和NHibernate 2.1.2.4000。

using System;
using System.Data.SqlClient;
using System.Transactions;

using FluentNHibernate.Mapping;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Cfg;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      var cfg =
        Fluently.Configure().Database(
          MsSqlConfiguration.MsSql2008.ConnectionString("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test").DefaultSchema("dbo")
        ).Mappings(x => x.FluentMappings.AddFromAssemblyOf<MyTableMap>()).BuildConfiguration();

      using (var sf = cfg.BuildSessionFactory())
      {
        using (var ts = new TransactionScope().PromoteToDtc())
        {
          using (var conn = new SqlConnection("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test"))
          {
            conn.Open();

            using (var session = sf.OpenSession(conn))
            {
              session.Save(new MyTable { String = "Hello!" });
            }
          }

          ts.Complete();
        }

        Console.WriteLine("It saved!");
        Console.ReadLine();
      }
    }
  }

  public class DummyEnlistmentNotification : IEnlistmentNotification
  {
    public static readonly Guid Id = new Guid("E2D35055-4187-4ff5-82A1-F1F161A008D0");

    public void Prepare(PreparingEnlistment preparingEnlistment)
    {
      preparingEnlistment.Prepared();
    }

    public void Commit(Enlistment enlistment)
    {
      enlistment.Done();
    }

    public void Rollback(Enlistment enlistment)
    {
      enlistment.Done();
    }

    public void InDoubt(Enlistment enlistment)
    {
      enlistment.Done();
    }
  }

  public static class TSExetensions
  {
    public static TransactionScope PromoteToDtc(this TransactionScope scope)
    {
      Transaction.Current.EnlistDurable(DummyEnlistmentNotification.Id, new DummyEnlistmentNotification(), EnlistmentOptions.None);
      return scope;
    }
  }

  public class MyTable
  {
    public virtual int Id { get; private set; }
    public virtual string String { get; set; }
  }

  public sealed class MyTableMap : ClassMap<MyTable>
  {
    public MyTableMap()
    {
      Id(x => x.Id).GeneratedBy.Native();
      Map(x => x.String).Not.Nullable();
    }
  }
}

NHibernate is throwning an exception when particpating in a distirbuted transaction and you've opened a session by specifying your own connection object.

Unhandled Exception: System.InvalidOperationException: Disconnect cannot be call
ed while a transaction is in progress.
   at NHibernate.AdoNet.ConnectionManager.Disconnect()
   at NHibernate.Impl.SessionImpl.Close()
   at NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing)
   at NHibernate.Transaction.AdoNetWithDistrubtedTransactionFactory.<>c__Display
Class1.<EnlistInDistributedTransactionIfNeeded>b__0(Object sender, TransactionEv
entArgs e)
   at System.Transactions.TransactionCompletedEventHandler.Invoke(Object sender,
 TransactionEventArgs e)
   at System.Transactions.TransactionStatePromotedCommitted.EnterState(InternalT
ransaction tx)
   at System.Transactions.InternalTransaction.DistributedTransactionOutcome(Inte
rnalTransaction tx, TransactionStatus status)
   at System.Transactions.Oletx.RealOletxTransaction.FireOutcome(TransactionStat
us statusArg)
   at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(Transact
ionStatus status)
   at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback
(Object state, Boolean timeout)
   at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback
(Object state, Boolean timedOut)

The following code will reproduce the issue; reference the current FluentNibernate, and NHibernate 2.1.2.4000.

using System;
using System.Data.SqlClient;
using System.Transactions;

using FluentNHibernate.Mapping;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Cfg;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      var cfg =
        Fluently.Configure().Database(
          MsSqlConfiguration.MsSql2008.ConnectionString("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test").DefaultSchema("dbo")
        ).Mappings(x => x.FluentMappings.AddFromAssemblyOf<MyTableMap>()).BuildConfiguration();

      using (var sf = cfg.BuildSessionFactory())
      {
        using (var ts = new TransactionScope().PromoteToDtc())
        {
          using (var conn = new SqlConnection("Integrated Security=SSPI;Data Source=.;Initial Catalog=Test"))
          {
            conn.Open();

            using (var session = sf.OpenSession(conn))
            {
              session.Save(new MyTable { String = "Hello!" });
            }
          }

          ts.Complete();
        }

        Console.WriteLine("It saved!");
        Console.ReadLine();
      }
    }
  }

  public class DummyEnlistmentNotification : IEnlistmentNotification
  {
    public static readonly Guid Id = new Guid("E2D35055-4187-4ff5-82A1-F1F161A008D0");

    public void Prepare(PreparingEnlistment preparingEnlistment)
    {
      preparingEnlistment.Prepared();
    }

    public void Commit(Enlistment enlistment)
    {
      enlistment.Done();
    }

    public void Rollback(Enlistment enlistment)
    {
      enlistment.Done();
    }

    public void InDoubt(Enlistment enlistment)
    {
      enlistment.Done();
    }
  }

  public static class TSExetensions
  {
    public static TransactionScope PromoteToDtc(this TransactionScope scope)
    {
      Transaction.Current.EnlistDurable(DummyEnlistmentNotification.Id, new DummyEnlistmentNotification(), EnlistmentOptions.None);
      return scope;
    }
  }

  public class MyTable
  {
    public virtual int Id { get; private set; }
    public virtual string String { get; set; }
  }

  public sealed class MyTableMap : ClassMap<MyTable>
  {
    public MyTableMap()
    {
      Id(x => x.Id).GeneratedBy.Native();
      Map(x => x.String).Not.Nullable();
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

分開簡單 2024-10-10 08:14:04

问题确实出在NHiberate 上。他们正在开发补丁。作为参考,可以在此处找到该问题

The issue is indeed with NHiberate. They're working on a patch. For reference, the issue can be found here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文