Question

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();
    }
  }
}
Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top