This seems to work fine, at least the basic test now passes.
Code:
Index: src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- src/NHibernate.Test/NHibernate.Test.csproj (revision 4808)
+++ src/NHibernate.Test/NHibernate.Test.csproj (working copy)
@@ -1296,6 +1296,7 @@
<Compile Include="SqlTest\Custom\CustomStoredProcSupportTest.cs" />
<Compile Include="SqlTest\Custom\MySQL\MySQLTest.cs" />
<Compile Include="SqlTest\Custom\Oracle\OracleCustomSQLFixture.cs" />
+ <Compile Include="SqlTest\Custom\MsSQL\Monkey.cs" />
<Compile Include="SqlTest\SqlTypeFactoryFixture.cs" />
<Compile Include="Stateless\Naturalness.cs" />
<Compile Include="Stateless\StatelessWithRelationsFixture.cs" />
@@ -2052,6 +2053,7 @@
<EmbeddedResource Include="CfgTest\Loquacious\EntityToCache.hbm.xml" />
<EmbeddedResource Include="DriverTest\SqlServerCeEntity.hbm.xml" />
<Content Include="DynamicEntity\package.html" />
+ <EmbeddedResource Include="SqlTest\Custom\MsSQL\Monkey.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2003\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1356\MappingsBag.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1356\MappingsList.hbm.xml" />
Index: src/NHibernate/Id/Enhanced/TableStructure.cs
===================================================================
--- src/NHibernate/Id/Enhanced/TableStructure.cs (revision 4808)
+++ src/NHibernate/Id/Enhanced/TableStructure.cs (working copy)
@@ -102,72 +102,88 @@
public override object DoWorkInCurrentTransaction(ISessionImplementor session, IDbConnection conn, IDbTransaction transaction)
{
long result;
- int rows;
+ bool updated;
+
do
{
- string query = select.ToString();
- SqlLog.Debug(query);
- IDbCommand qps = conn.CreateCommand();
- IDataReader rs = null;
- qps.CommandText = query;
- qps.CommandType = CommandType.Text;
- qps.Transaction = conn.BeginTransaction();
- try
- {
- rs = qps.ExecuteReader();
- if (!rs.Read())
- {
- string err = "could not read a hi value - you need to populate the table: " + tableName;
- log.Error(err);
- throw new IdentifierGenerationException(err);
- }
- result = rs.GetInt64(0);
- rs.Close();
- }
- catch (Exception sqle)
- {
- log.Error("could not read a hi value", sqle);
- throw;
- }
- finally
- {
- if (rs != null) rs.Close();
- qps.Dispose();
- }
+ result = QueryCurrentHi(session, conn, transaction);
+ updated = UpdateNextHi(session, conn, transaction, result);
+ } while (!updated);
- query = update.ToString();
-
- IDbCommand ups = conn.CreateCommand();
- ups.CommandType = CommandType.Text;
- ups.CommandText = query;
- ups.Connection = conn;
- ups.Transaction = conn.BeginTransaction();
- try
- {
- int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
- ((IDataParameter) ups.Parameters[0]).Value = result + increment;
- ((IDataParameter)ups.Parameters[1]).Value = result;
- rows = ups.ExecuteNonQuery();
- }
- catch (Exception sqle)
- {
- log.Error("could not update hi value in: " + tableName, sqle);
- throw;
- }
- finally
- {
- ups.Dispose();
- }
- }
- while (rows == 0);
-
accessCounter++;
return result;
}
- #endregion
+ private long QueryCurrentHi(ISessionImplementor session, IDbConnection conn, IDbTransaction transaction)
+ {
+ long result;
+ IDbCommand qps = session.Factory.ConnectionProvider.Driver.GenerateCommand(CommandType.Text, select, SqlTypeFactory.NoTypes);
+ IDataReader rs = null;
+ qps.Connection = conn;
+ qps.Transaction = transaction;
+
+ SqlLog.Debug(qps.CommandText);
+
+ try
+ {
+ rs = qps.ExecuteReader();
+ if (!rs.Read())
+ {
+ string err = "could not read a hi value - you need to populate the table: " + tableName;
+ log.Error(err);
+ throw new IdentifierGenerationException(err);
+ }
+ result = rs.GetInt64(0);
+ rs.Close();
+ }
+ catch (Exception sqle)
+ {
+ log.Error("could not read a hi value", sqle);
+ throw;
+ }
+ finally
+ {
+ if (rs != null) rs.Close();
+ qps.Dispose();
+ }
+
+ return result;
+ }
+
+ private bool UpdateNextHi(ISessionImplementor session, IDbConnection conn, IDbTransaction transaction, long result)
+ {
+ bool updated;
+
+ IDbCommand ups = session.Factory.ConnectionProvider.Driver.GenerateCommand(CommandType.Text, update, new[] {SqlTypeFactory.Int64, SqlTypeFactory.Int64});
+ ups.Connection = conn;
+ ups.Transaction = transaction;
+
+ SqlLog.Debug(ups.CommandText);
+
+ try
+ {
+ int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
+ ((IDataParameter)ups.Parameters[0]).Value = result + increment;
+ ((IDataParameter)ups.Parameters[1]).Value = result;
+ updated = ups.ExecuteNonQuery() != 0;
+ }
+ catch (Exception sqle)
+ {
+ log.Error("could not update hi value in: " + tableName, sqle);
+ throw;
+ }
+ finally
+ {
+ ups.Dispose();
+ }
+
+ return updated;
+ }
+
+ #endregion
+
#region Nested type: TableAccessCallback
private class TableAccessCallback : IAccessCallback
Code:
using System.Collections;
using NUnit.Framework;
namespace NHibernate.Test.SqlTest.Custom.MsSQL
{
[TestFixture]
public class MonkeyTests : TestCase
{
protected override string MappingsAssembly
{
get
{
return "NHibernate.Test";
}
}
protected override IList Mappings
{
get { return new[] {"SqlTest.Custom.MsSQL.Monkey.hbm.xml"}; }
}
[Test]
public void CanGenerateIdWithTransactionOpen()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var monkey1 = new Monkey();
var monkey2 = new Monkey();
Assert.AreEqual(0, monkey1.Id);
Assert.AreEqual(0, monkey1.Id);
session.Save(monkey1);
session.Save(monkey2);
Assert.AreEqual(1, monkey1.Id);
Assert.AreEqual(2, monkey2.Id);
session.Flush();
transaction.Rollback();
}
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var monkey = new Monkey();
Assert.AreEqual(0, monkey.Id);
session.Save(monkey);
Assert.AreEqual(3, monkey.Id);
session.Flush();
transaction.Rollback();
}
}
}
public class Monkey
{
public virtual int Id { get; set; }
}
}
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernate.Test"
namespace="NHibernate.Test.SqlTest.Custom.MsSQL">
<class name="Monkey">
<id name="Id" column="id">
<generator class="NHibernate.Id.Enhanced.SequenceStyleGenerator, NHibernate" />
<!--<generator class="hilo" />-->
</id>
</class>
</hibernate-mapping>