|
From: <fab...@us...> - 2008-08-15 21:41:40
|
Revision: 3706
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3706&view=rev
Author: fabiomaulo
Date: 2008-08-15 21:41:48 +0000 (Fri, 15 Aug 2008)
Log Message:
-----------
Start port of enhanced Id generators.
Possible breaking change:
- IPersistentIdentifierGenerator
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs
trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs
trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs
trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs
trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs
trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs
trunk/nhibernate/src/NHibernate/Id/Assigned.cs
trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs
trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs
trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs
trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs
trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs
trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs
trunk/nhibernate/src/NHibernate/Mapping/Table.cs
trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Engine/Transaction/
trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs
trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs
trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/
trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs
trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs
trunk/nhibernate/src/NHibernate.Test/IdGen/
trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/
trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs
Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -701,9 +701,14 @@
IEnumerable<IPersistentIdentifierGenerator> pIDg = IterateGenerators(dialect);
foreach (IPersistentIdentifierGenerator idGen in pIDg)
{
- string dropString = idGen.SqlDropString(dialect);
- if (dropString != null)
- script.Add(dropString);
+ string[] lines = idGen.SqlDropString(dialect);
+ if (lines != null)
+ {
+ foreach (string line in lines)
+ {
+ script.Add(line);
+ }
+ }
}
return script.ToArray();
Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -393,7 +393,7 @@
/// <summary>
/// Completely optional cascading drop clause
/// </summary>
- protected virtual string CascadeConstraintsString
+ public virtual string CascadeConstraintsString
{
get { return String.Empty; }
}
@@ -669,7 +669,7 @@
/// <summary>
/// Does the dialect support the syntax 'drop table if exists NAME'
/// </summary>
- protected virtual bool SupportsIfExistsBeforeTableName
+ public virtual bool SupportsIfExistsBeforeTableName
{
get { return false; }
}
@@ -677,7 +677,7 @@
/// <summary>
/// Does the dialect support the syntax 'drop table NAME if exists'
/// </summary>
- protected virtual bool SupportsIfExistsAfterTableName
+ public virtual bool SupportsIfExistsAfterTableName
{
get { return false; }
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/MySQLDialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -112,7 +112,7 @@
get { return '`'; }
}
- protected override bool SupportsIfExistsBeforeTableName
+ public override bool SupportsIfExistsBeforeTableName
{
get { return true; }
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/Oracle9Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -162,7 +162,7 @@
}
/// <summary></summary>
- protected override string CascadeConstraintsString
+ public override string CascadeConstraintsString
{
get { return " cascade constraints"; }
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/PostgreSQL82Dialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -18,7 +18,7 @@
RegisterColumnType(DbType.Guid, "uuid");
}
- protected override bool SupportsIfExistsBeforeTableName
+ public override bool SupportsIfExistsBeforeTableName
{
get { return true; }
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/PostgreSQLDialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -77,7 +77,7 @@
get { return false; }
}
- protected override string CascadeConstraintsString
+ public override string CascadeConstraintsString
{
get { return " cascade"; }
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Dialect/SQLiteDialect.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -79,7 +79,7 @@
get { return true; }
}
- protected override bool SupportsIfExistsBeforeTableName
+ public override bool SupportsIfExistsBeforeTableName
{
get { return true; }
}
Added: trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Engine/Transaction/IIsolatedWork.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,18 @@
+using System.Data;
+
+namespace NHibernate.Engine.Transaction
+{
+ /// <summary>
+ /// Represents work that needs to be performed in a manner
+ /// which isolates it from any current application unit of
+ /// work transaction.
+ /// </summary>
+ public interface IIsolatedWork
+ {
+ /// <summary>
+ /// Perform the actual work to be done.
+ /// </summary>
+ /// <param name="connection">The ADP cpnnection to use.</param>
+ void DoWork(IDbConnection connection);
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Engine/Transaction/Isolater.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,150 @@
+using System;
+using System.Data;
+using System.Data.Common;
+using log4net;
+using NHibernate.Exceptions;
+
+namespace NHibernate.Engine.Transaction
+{
+ /// <summary>
+ /// Class which provides the isolation semantics required by
+ /// an <see cref="IIsolatedWork"/>.
+ /// </summary>
+ /// <remarks>
+ /// <list type="bullet">
+ /// <listheader>
+ /// <description>Processing comes in two flavors:</description>
+ /// </listheader>
+ /// <item>
+ /// <term><see cref="DoIsolatedWork"/> </term>
+ /// <description>makes sure the work to be done is performed in a seperate, distinct transaction</description>
+ /// </item>
+ /// <item>
+ /// <term><see cref="DoNonTransactedWork"/> </term>
+ /// <description>makes sure the work to be done is performed outside the scope of any transaction</description>
+ /// </item>
+ /// </list>
+ /// </remarks>
+ public class Isolater
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof(Isolater));
+
+ private static DoWork GetApropieateDelegate()
+ {
+ bool isAmbientTransation = System.Transactions.Transaction.Current != null;
+ if (isAmbientTransation)
+ {
+ return AmbientDelegateWork;
+ }
+ else
+ {
+ return AdoDelegateWork;
+ }
+ }
+ /// <summary>
+ /// Ensures that all processing actually performed by the given work will
+ /// occur on a seperate transaction.
+ /// </summary>
+ /// <param name="work">The work to be performed. </param>
+ /// <param name="session">The session from which this request is originating. </param>
+ public static void DoIsolatedWork(IIsolatedWork work, ISessionImplementor session)
+ {
+ DoWork worker = GetApropieateDelegate();
+ worker(session, work, true);
+ }
+
+ /// <summary>
+ /// Ensures that all processing actually performed by the given work will
+ /// occur outside of a transaction.
+ /// </summary>
+ /// <param name="work">The work to be performed. </param>
+ /// <param name="session">The session from which this request is originating. </param>
+ public static void DoNonTransactedWork(IIsolatedWork work, ISessionImplementor session)
+ {
+ DoWork worker = GetApropieateDelegate();
+ worker(session, work, false);
+ }
+
+ private delegate void DoWork(ISessionImplementor session, IIsolatedWork work, bool transacted);
+
+ private static void AdoDelegateWork(ISessionImplementor session, IIsolatedWork work, bool transacted)
+ {
+ IDbConnection connection = null;
+ IDbTransaction trans = null;
+ // bool wasAutoCommit = false;
+ try
+ {
+ connection = session.Factory.ConnectionProvider.GetConnection();
+
+ if (transacted)
+ {
+ trans = connection.BeginTransaction();
+ // TODO NH: a way to read the autocommit state is needed
+ //if (TransactionManager.GetAutoCommit(connection))
+ //{
+ // wasAutoCommit = true;
+ // TransactionManager.SetAutoCommit(connection, false);
+ //}
+ }
+
+ work.DoWork(connection);
+
+ if (transacted)
+ {
+ trans.Commit();
+ //TransactionManager.Commit(connection);
+ }
+ }
+ catch (Exception t)
+ {
+ try
+ {
+ if (transacted && connection != null && !(connection.State == ConnectionState.Closed))
+ {
+ trans.Rollback();
+ // TransactionManager.RollBack(connection);
+ }
+ }
+ catch (Exception ignore)
+ {
+ log.Debug("unable to release connection on exception [" + ignore + "]");
+ }
+
+ if (t is HibernateException)
+ {
+ throw;
+ }
+ else if (t is DbException)
+ {
+ throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, "error performing isolated work");
+ }
+ else
+ {
+ throw new HibernateException("error performing isolated work", t);
+ }
+ }
+ finally
+ {
+ //if (transacted && wasAutoCommit)
+ //{
+ // try
+ // {
+ // // TODO NH: reset autocommit
+ // // TransactionManager.SetAutoCommit(connection, true);
+ // }
+ // catch (Exception)
+ // {
+ // log.Debug("was unable to reset connection back to auto-commit");
+ // }
+ //}
+ session.Factory.ConnectionProvider.CloseConnection(connection);
+ }
+ }
+
+ private static void AmbientDelegateWork(ISessionImplementor session, IIsolatedWork work, bool transacted)
+ {
+ throw new NotSupportedException("Not supported yet.");
+ }
+
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Engine/TransactionHelper.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,53 @@
+using System.Data;
+using NHibernate.Engine.Transaction;
+using NHibernate.Exceptions;
+
+namespace NHibernate.Engine
+{
+ /// <summary>
+ /// Allows work to be done outside the current transaction, by suspending it,
+ /// and performing work in a new transaction
+ /// </summary>
+ public abstract class TransactionHelper
+ {
+ public class Work : IIsolatedWork
+ {
+ private readonly ISessionImplementor session;
+ private readonly TransactionHelper owner;
+ internal object generatedValue;
+
+ public Work(ISessionImplementor session, TransactionHelper owner)
+ {
+ this.session = session;
+ this.owner = owner;
+ }
+
+ #region Implementation of IIsolatedWork
+
+ public void DoWork(IDbConnection connection)
+ {
+ try
+ {
+ generatedValue = owner.DoWorkInCurrentTransaction(connection, null);
+ }
+ catch (System.Data.OleDb.OleDbException sqle)
+ {
+ throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "could not get or update next value", null);
+ }
+ }
+
+ #endregion
+ }
+
+ /// <summary> The work to be done</summary>
+ public abstract object DoWorkInCurrentTransaction(IDbConnection conn, string sql);
+
+ /// <summary> Suspend the current transaction and perform work in a new transaction</summary>
+ public virtual object DoWorkInNewTransaction(ISessionImplementor session)
+ {
+ Work work = new Work(session, this);
+ Isolater.DoIsolatedWork(work, session);
+ return work.generatedValue;
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Id/Assigned.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Assigned.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/Assigned.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -52,7 +52,7 @@
#region IConfigurable Members
- public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d)
+ public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
{
parms.TryGetValue(IdGeneratorParmsNames.EntityName, out entityName);
if (entityName == null)
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IAccessCallback.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,12 @@
+namespace NHibernate.Id.Enhanced
+{
+ /// <summary>
+ /// Contract for providing callback access to a <see cref="IDatabaseStructure"/>,
+ /// typically from the <see cref="IOptimizer"/>.
+ /// </summary>
+ public interface IAccessCallback
+ {
+ /// <summary> Retrieve the next value from the underlying source. </summary>
+ long NextValue { get;}
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IDatabaseStructure.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,44 @@
+using NHibernate.Engine;
+
+namespace NHibernate.Id.Enhanced
+{
+ /// <summary>
+ /// Encapsulates definition of the underlying data structure backing a sequence-style generator.
+ /// </summary>
+ public interface IDatabaseStructure
+ {
+ /// <summary> The name of the database structure (table or sequence).</summary>
+ string Name { get; }
+
+ /// <summary> How many times has this structure been accessed through this reference?</summary>
+ int TimesAccessed { get; }
+
+ /// <summary> The configured increment size</summary>
+ int IncrementSize { get; }
+
+ /// <summary>
+ /// A callback to be able to get the next value from the underlying
+ /// structure as needed.
+ /// </summary>
+ /// <param name="session">The session. </param>
+ /// <returns> The next value. </returns>
+ IAccessCallback BuildCallback(ISessionImplementor session);
+
+ /// <summary>
+ /// Prepare this structure for use. Called sometime after instantiation,
+ /// but before first use.
+ /// </summary>
+ /// <param name="optimizer">The optimizer being applied to the generator. </param>
+ void Prepare(IOptimizer optimizer);
+
+ /// <summary> Commands needed to create the underlying structures.</summary>
+ /// <param name="dialect">The database dialect being used. </param>
+ /// <returns> The creation commands. </returns>
+ string[] SqlCreateStrings(Dialect.Dialect dialect);
+
+ /// <summary> Commands needed to drop the underlying structures.</summary>
+ /// <param name="dialect">The database dialect being used. </param>
+ /// <returns> The drop commands. </returns>
+ string[] SqlDropStrings(Dialect.Dialect dialect);
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/IOptimizer.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,54 @@
+namespace NHibernate.Id.Enhanced
+{
+ /// <summary>
+ /// Performs optimization on an optimizable identifier generator. Typically
+ /// this optimization takes the form of trying to ensure we do not have to
+ /// hit the database on each and every request to get an identifier value.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// Optimizers work on constructor injection. They should provide
+ /// a constructor with the following arguments.
+ /// </para>
+ /// - <see cref="System.Type"/> The return type for the generated values.
+ /// - <langword>int</langword> The increment size.
+ /// </remarks>
+ public interface IOptimizer
+ {
+ /// <summary>
+ /// A common means to access the last value obtained from the underlying
+ /// source. This is intended for testing purposes, since accessing the
+ /// unerlying database source directly is much more difficult.
+ /// </summary>
+ /// <value>
+ /// The last value we obtained from the underlying source;
+ /// -1 indicates we have not yet consulted with the source.
+ /// </value>
+ long LastSourceValue{get;}
+ /// <summary>
+ /// Defined increment size.
+ /// </summary>
+ /// <value> The increment size.
+ /// </value>
+ int IncrementSize{get;}
+
+ /// <summary>
+ /// Generate an identifier value accounting for this specific optimization.
+ /// </summary>
+ /// <param name="callback">Callback to access the underlying value source. </param>
+ /// <returns> The generated identifier value. </returns>
+ object Generate(IAccessCallback callback);
+
+ /// <summary>
+ /// Are increments to be applied to the values stored in the underlying
+ /// value source?
+ /// </summary>
+ /// <returns>
+ /// True if the values in the source are to be incremented
+ /// according to the defined increment size; false otherwise, in which
+ /// case the increment is totally an in memory construct.
+ /// </returns>
+ bool ApplyIncrementSizeToSourceValues { get;}
+
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/OptimizerFactory.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,265 @@
+using System;
+using System.Reflection;
+using log4net;
+using NHibernate.Util;
+
+namespace NHibernate.Id.Enhanced
+{
+ public class OptimizerFactory
+ {
+ public const string HiLo = "hilo";
+ public const string None = "none";
+ public const string Pool = "pooled";
+ private static readonly System.Type[] CtorSignature = new System.Type[] {typeof (System.Type), typeof (int)};
+ private static readonly ILog log = LogManager.GetLogger(typeof (OptimizerFactory));
+
+ public static IOptimizer BuildOptimizer(string type, System.Type returnClass, int incrementSize)
+ {
+ if (string.IsNullOrEmpty(type))
+ {
+ throw new ArgumentNullException("type");
+ }
+ if (returnClass == null)
+ {
+ throw new ArgumentNullException("returnClass");
+ }
+ string optimizerClassName;
+ switch (type)
+ {
+ case None:
+ optimizerClassName = typeof (NoopOptimizer).FullName;
+ break;
+ case HiLo:
+ optimizerClassName = typeof (HiLoOptimizer).FullName;
+ break;
+ case Pool:
+ optimizerClassName = typeof (PooledOptimizer).FullName;
+ break;
+ default:
+ optimizerClassName = type;
+ break;
+ }
+
+ try
+ {
+ System.Type optimizerClass = ReflectHelper.ClassForName(optimizerClassName);
+ ConstructorInfo ctor = optimizerClass.GetConstructor(CtorSignature);
+ return (IOptimizer)ctor.Invoke(new object[] { returnClass, incrementSize });
+ }
+ catch (Exception)
+ {
+ // intentionally empty
+ }
+
+ // the default...
+ return new NoopOptimizer(returnClass, incrementSize);
+ }
+
+ #region Nested type: HiLoOptimizer
+
+ public class HiLoOptimizer : OptimizerSupport
+ {
+ private long hiValue;
+ private long lastSourceValue = -1;
+ private long value_Renamed;
+
+ public HiLoOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize)
+ {
+ if (incrementSize < 1)
+ {
+ throw new HibernateException("increment size cannot be less than 1");
+ }
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("creating hilo optimizer with [incrementSize=" + incrementSize + "; returnClass=" + returnClass.FullName
+ + "]");
+ }
+ }
+
+ public override long LastSourceValue
+ {
+ get { return lastSourceValue; }
+ }
+
+ public long LastValue
+ {
+ get { return value_Renamed - 1; }
+ }
+
+ public long HiValue
+ {
+ get { return hiValue; }
+ }
+
+ public override bool ApplyIncrementSizeToSourceValues
+ {
+ get { return false; }
+ }
+
+ public override object Generate(IAccessCallback callback)
+ {
+ if (lastSourceValue < 0)
+ {
+ lastSourceValue = callback.NextValue;
+ while (lastSourceValue <= 0)
+ {
+ lastSourceValue = callback.NextValue;
+ }
+ hiValue = (lastSourceValue * incrementSize) + 1;
+ value_Renamed = hiValue - incrementSize;
+ }
+ else if (value_Renamed >= hiValue)
+ {
+ lastSourceValue = callback.NextValue;
+ hiValue = (lastSourceValue * incrementSize) + 1;
+ }
+ return Make(value_Renamed++);
+ }
+ }
+
+ #endregion
+
+ #region Nested type: NoopOptimizer
+
+ public class NoopOptimizer : OptimizerSupport
+ {
+ private long lastSourceValue = -1;
+
+ public NoopOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize) {}
+
+ public override long LastSourceValue
+ {
+ get { return lastSourceValue; }
+ }
+
+ public override bool ApplyIncrementSizeToSourceValues
+ {
+ get { return false; }
+ }
+
+ public override object Generate(IAccessCallback callback)
+ {
+ if (lastSourceValue == -1)
+ {
+ while (lastSourceValue <= 0)
+ {
+ lastSourceValue = callback.NextValue;
+ }
+ }
+ else
+ {
+ lastSourceValue = callback.NextValue;
+ }
+ return Make(lastSourceValue);
+ }
+ }
+
+ #endregion
+
+ #region Nested type: OptimizerSupport
+
+ public abstract class OptimizerSupport : IOptimizer
+ {
+ protected int incrementSize;
+ protected System.Type returnClass;
+
+ protected OptimizerSupport(System.Type returnClass, int incrementSize)
+ {
+ if (returnClass == null)
+ {
+ throw new HibernateException("return class is required");
+ }
+ this.returnClass = returnClass;
+ this.incrementSize = incrementSize;
+ }
+
+ public System.Type ReturnClass
+ {
+ get { return returnClass; }
+ }
+
+ #region IOptimizer Members
+
+ public int IncrementSize
+ {
+ get { return incrementSize; }
+ }
+
+ public abstract long LastSourceValue { get; }
+
+ public abstract bool ApplyIncrementSizeToSourceValues { get; }
+ public abstract object Generate(IAccessCallback param);
+
+ #endregion
+
+ protected virtual object Make(long value)
+ {
+ return IdentifierGeneratorFactory.CreateNumber(value, returnClass);
+ }
+ }
+
+ #endregion
+
+ #region Nested type: PooledOptimizer
+
+ public class PooledOptimizer : OptimizerSupport
+ {
+ private long hiValue = -1;
+ private long value_Renamed;
+
+ public PooledOptimizer(System.Type returnClass, int incrementSize) : base(returnClass, incrementSize)
+ {
+ if (incrementSize < 1)
+ {
+ throw new HibernateException("increment size cannot be less than 1");
+ }
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("creating pooled optimizer with [incrementSize=" + incrementSize + "; returnClass="
+ + returnClass.FullName + "]");
+ }
+ }
+
+ public override long LastSourceValue
+ {
+ get { return hiValue; }
+ }
+
+ public long LastValue
+ {
+ get { return value_Renamed - 1; }
+ }
+
+ public override bool ApplyIncrementSizeToSourceValues
+ {
+ get { return true; }
+ }
+
+ public override object Generate(IAccessCallback callback)
+ {
+ if (hiValue < 0)
+ {
+ value_Renamed = callback.NextValue;
+ if (value_Renamed < 1)
+ {
+ // unfortunately not really safe to normalize this
+ // to 1 as an initial value like we do the others
+ // because we would not be able to control this if
+ // we are using a sequence...
+ log.Info("pooled optimizer source reported [" + value_Renamed
+ + "] as the initial value; use of 1 or greater highly recommended");
+ }
+ hiValue = callback.NextValue;
+ }
+ else if (value_Renamed >= hiValue)
+ {
+ hiValue = callback.NextValue;
+ value_Renamed = hiValue - incrementSize;
+ }
+ return Make(value_Renamed++);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStructure.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,140 @@
+using System;
+using System.Data;
+using System.Data.Common;
+using log4net;
+using NHibernate.Engine;
+using NHibernate.Exceptions;
+using NHibernate.SqlCommand;
+using NHibernate.SqlTypes;
+
+namespace NHibernate.Id.Enhanced
+{
+ /// <summary>
+ /// Describes a sequence.
+ /// </summary>
+ public class SequenceStructure : IDatabaseStructure
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof (SequenceStructure));
+ private readonly int incrementSize;
+ private readonly int initialValue;
+ private readonly string sequenceName;
+ private readonly SqlString sql;
+ private int accessCounter;
+ private bool applyIncrementSizeToSourceValues;
+
+ public SequenceStructure(Dialect.Dialect dialect, string sequenceName, int initialValue, int incrementSize)
+ {
+ this.sequenceName = sequenceName;
+ this.initialValue = initialValue;
+ this.incrementSize = incrementSize;
+ sql = new SqlString(dialect.GetSequenceNextValString(sequenceName));
+ }
+
+ #region IDatabaseStructure Members
+
+ public string Name
+ {
+ get { return sequenceName; }
+ }
+
+ public int IncrementSize
+ {
+ get { return incrementSize; }
+ }
+
+ public IAccessCallback BuildCallback(ISessionImplementor session)
+ {
+ return new SequenceAccessCallback(session, this);
+ }
+
+ public void Prepare(IOptimizer optimizer)
+ {
+ applyIncrementSizeToSourceValues = optimizer.ApplyIncrementSizeToSourceValues;
+ }
+
+ public string[] SqlCreateStrings(Dialect.Dialect dialect)
+ {
+ int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1;
+ return dialect.GetCreateSequenceStrings(sequenceName, initialValue, sourceIncrementSize);
+ }
+
+ public string[] SqlDropStrings(Dialect.Dialect dialect)
+ {
+ return dialect.GetDropSequenceStrings(sequenceName);
+ }
+
+ public int TimesAccessed
+ {
+ get { return accessCounter; }
+ }
+
+ #endregion
+
+ #region Nested type: SequenceAccessCallback
+
+ private class SequenceAccessCallback : IAccessCallback
+ {
+ private readonly SequenceStructure owner;
+ private readonly ISessionImplementor session;
+
+ public SequenceAccessCallback(ISessionImplementor session, SequenceStructure owner)
+ {
+ this.session = session;
+ this.owner = owner;
+ }
+
+ #region IAccessCallback Members
+
+ public virtual long NextValue
+ {
+ get
+ {
+ owner.accessCounter++;
+ try
+ {
+ IDbCommand st = session.Batcher.PrepareCommand(CommandType.Text, owner.sql, new SqlType[] {SqlTypeFactory.Int64});
+ IDataReader rs = null;
+ try
+ {
+ rs = session.Batcher.ExecuteReader(st);
+ try
+ {
+ rs.Read();
+ long result = rs.GetInt64(0);
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Sequence identifier generated: " + result);
+ }
+ return result;
+ }
+ finally
+ {
+ try
+ {
+ rs.Close();
+ }
+ catch (Exception ignore)
+ {
+ // intentionally empty
+ }
+ }
+ }
+ finally
+ {
+ session.Batcher.CloseCommand(st, rs);
+ }
+ }
+ catch (DbException sqle)
+ {
+ throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, sqle, "could not get next sequence value",
+ owner.sql);
+ }
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/SequenceStyleGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,133 @@
+using System.Collections.Generic;
+using log4net;
+using NHibernate.Engine;
+using NHibernate.Mapping;
+using NHibernate.Type;
+using NHibernate.Util;
+
+namespace NHibernate.Id.Enhanced
+{
+ public class SequenceStyleGenerator : IPersistentIdentifierGenerator, IConfigurable
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof(SequenceStyleGenerator));
+
+ #region General purpose parameters
+
+ public const string SequenceParam = "sequence_name";
+ public const string DefaultSequenceName = "hibernate_sequence";
+
+ public const string InitialParam = "initial_value";
+ public const int DefaultInitialValue = 1;
+
+ public const string IncrementParam= "increment_size";
+ public const int DefaultIncrementSize = 1;
+
+ public const string OptimizerParam= "optimizer";
+
+ public const string ForceTableParam = "force_table_use";
+
+ #endregion
+
+ #region table-specific parameters
+
+ public const string ValueColumnParam= "value_column";
+ public const string DefaultValueColumnName = "next_val";
+
+ #endregion
+
+ private IDatabaseStructure databaseStructure;
+ private IOptimizer optimizer;
+ private IType identifierType;
+
+ public IDatabaseStructure DatabaseStructure
+ {
+ get { return databaseStructure; }
+ }
+
+ public IOptimizer Optimizer
+ {
+ get { return optimizer; }
+ }
+
+ public IType IdentifierType
+ {
+ get { return identifierType; }
+ }
+
+ #region Implementation of IIdentifierGenerator
+
+ public virtual object Generate(ISessionImplementor session, object obj)
+ {
+ return optimizer.Generate(databaseStructure.BuildCallback(session));
+ }
+
+ #endregion
+
+ #region Implementation of IPersistentIdentifierGenerator
+
+ public virtual string[] SqlCreateStrings(Dialect.Dialect dialect)
+ {
+ return databaseStructure.SqlCreateStrings(dialect);
+ }
+
+ public virtual string[] SqlDropString(Dialect.Dialect dialect)
+ {
+ return databaseStructure.SqlDropStrings(dialect);
+ }
+
+ public virtual string GeneratorKey()
+ {
+ return databaseStructure.Name;
+ }
+
+ #endregion
+
+ #region Implementation of IConfigurable
+
+ public virtual void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
+ {
+ identifierType = type;
+ bool forceTableUse = PropertiesHelper.GetBoolean(ForceTableParam, parms, false);
+
+ string sequenceName = PropertiesHelper.GetString(SequenceParam, parms, DefaultSequenceName);
+ if (sequenceName.IndexOf('.') < 0)
+ {
+ string schemaName;
+ string catalogName;
+ parms.TryGetValue(PersistentIdGeneratorParmsNames.Schema, out schemaName);
+ parms.TryGetValue(PersistentIdGeneratorParmsNames.Catalog, out catalogName);
+ sequenceName = Table.Qualify(catalogName, schemaName, sequenceName);
+ }
+ int initialValue = PropertiesHelper.GetInt32(InitialParam, parms, DefaultInitialValue);
+ int incrementSize = PropertiesHelper.GetInt32(IncrementParam, parms, DefaultIncrementSize);
+
+ string valueColumnName = PropertiesHelper.GetString(ValueColumnParam, parms, DefaultValueColumnName);
+
+ string defOptStrategy = incrementSize <= 1 ? OptimizerFactory.None : OptimizerFactory.Pool;
+ string optimizationStrategy = PropertiesHelper.GetString(OptimizerParam, parms, defOptStrategy);
+ if (OptimizerFactory.None.Equals(optimizationStrategy) && incrementSize > 1)
+ {
+ log.Warn("config specified explicit optimizer of [" + OptimizerFactory.None + "], but [" + IncrementParam + "=" + incrementSize + "; honoring optimizer setting");
+ incrementSize = 1;
+ }
+ if (dialect.SupportsSequences && !forceTableUse)
+ {
+ if (OptimizerFactory.Pool.Equals(optimizationStrategy) && !dialect.SupportsPooledSequences)
+ {
+ // TODO : may even be better to fall back to a pooled table strategy here so that the db stored values remain consistent...
+ optimizationStrategy = OptimizerFactory.HiLo;
+ }
+ databaseStructure = new SequenceStructure(dialect, sequenceName, initialValue, incrementSize);
+ }
+ else
+ {
+ databaseStructure = new TableStructure(dialect, sequenceName, valueColumnName, initialValue, incrementSize);
+ }
+
+ optimizer = OptimizerFactory.BuildOptimizer(optimizationStrategy, identifierType.ReturnedClass, incrementSize);
+ databaseStructure.Prepare(optimizer);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Enhanced/TableStructure.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,198 @@
+using System;
+using System.Data;
+using System.Text;
+using log4net;
+using NHibernate.Engine;
+using NHibernate.SqlCommand;
+using NHibernate.SqlTypes;
+
+namespace NHibernate.Id.Enhanced
+{
+ /// <summary>
+ /// Describes a table used to mimic sequence behavior
+ /// </summary>
+ public class TableStructure : TransactionHelper, IDatabaseStructure
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof (IDatabaseStructure));
+ private static readonly ILog SqlLog = LogManager.GetLogger("NHibernate.SQL");
+ private readonly int incrementSize;
+ private readonly int initialValue;
+ private readonly string tableName;
+ private readonly string valueColumnName;
+ private int accessCounter;
+ private bool applyIncrementSizeToSourceValues;
+ private readonly SqlString select;
+ private readonly SqlString update;
+
+ public TableStructure(Dialect.Dialect dialect, string tableName, string valueColumnName, int initialValue,
+ int incrementSize)
+ {
+ this.tableName = tableName;
+ this.valueColumnName = valueColumnName;
+ this.initialValue = initialValue;
+ this.incrementSize = incrementSize;
+
+ SqlStringBuilder b = new SqlStringBuilder();
+ b.Add("select ").Add(valueColumnName).Add(" id_val").Add(" from ").Add(dialect.AppendLockHint(LockMode.Upgrade,
+ tableName)).Add(
+ dialect.ForUpdateString);
+ select = b.ToSqlString();
+
+ b = new SqlStringBuilder();
+ b.Add("update ").Add(tableName).Add(" set ").Add(valueColumnName).Add(" = ").Add(Parameter.Placeholder).Add(" where ")
+ .Add(valueColumnName).Add(" = ").Add(Parameter.Placeholder);
+ update = b.ToSqlString();
+ }
+
+ #region Implementation of IDatabaseStructure
+
+ public string Name
+ {
+ get { return tableName; }
+ }
+
+ public int TimesAccessed
+ {
+ get { return accessCounter; }
+ }
+
+ public int IncrementSize
+ {
+ get { return incrementSize; }
+ }
+
+ public virtual IAccessCallback BuildCallback(ISessionImplementor session)
+ {
+ return new TableAccessCallback(session, this);
+ }
+
+ public virtual void Prepare(IOptimizer optimizer)
+ {
+ applyIncrementSizeToSourceValues = optimizer.ApplyIncrementSizeToSourceValues;
+ }
+
+ public virtual string[] SqlCreateStrings(Dialect.Dialect dialect)
+ {
+ return new String[]
+ {
+ "create table " + tableName + " ( " + valueColumnName + " " + dialect.GetTypeName(SqlTypeFactory.Int64)
+ + " )", "insert into " + tableName + " values ( " + initialValue + " )"
+ };
+ }
+
+ public virtual string[] SqlDropStrings(Dialect.Dialect dialect)
+ {
+ StringBuilder sqlDropString = new StringBuilder().Append("drop table ");
+ if (dialect.SupportsIfExistsBeforeTableName)
+ {
+ sqlDropString.Append("if exists ");
+ }
+ sqlDropString.Append(tableName).Append(dialect.CascadeConstraintsString);
+ if (dialect.SupportsIfExistsAfterTableName)
+ {
+ sqlDropString.Append(" if exists");
+ }
+ return new String[] {sqlDropString.ToString()};
+ }
+
+ #endregion
+
+ #region Overrides of TransactionHelper
+
+ public override object DoWorkInCurrentTransaction(IDbConnection conn, string sql)
+ {
+ long result;
+ int rows;
+ 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();
+ }
+
+ query = update.ToString();
+ SqlLog.Debug(sql);
+ 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
+
+ #region Nested type: TableAccessCallback
+
+ private class TableAccessCallback : IAccessCallback
+ {
+ private readonly TableStructure owner;
+ private readonly ISessionImplementor session;
+
+ public TableAccessCallback(ISessionImplementor session, TableStructure owner)
+ {
+ this.session = session;
+ this.owner = owner;
+ }
+
+ #region IAccessCallback Members
+
+ public virtual long NextValue
+ {
+ get { return Convert.ToInt64(owner.DoWorkInNewTransaction(session)); }
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/ForeignGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -82,11 +82,11 @@
/// </summary>
/// <param name="type">The <see cref="IType"/> the identifier should be.</param>
/// <param name="parms">An <see cref="IDictionary"/> of Param values that are keyed by parameter name.</param>
- /// <param name="d">The <see cref="Dialect.Dialect"/> to help with Configuration.</param>
+ /// <param name="dialect">The <see cref="Dialect.Dialect"/> to help with Configuration.</param>
/// <exception cref="MappingException">
/// Thrown if the key <c>property</c> is not found in the <c>parms</c> parameter.
/// </exception>
- public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d)
+ public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
{
parms.TryGetValue(IdGeneratorParmsNames.EntityName, out entityName);
parms.TryGetValue("property", out propertyName);
Modified: trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/IConfigurable.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -16,7 +16,7 @@
/// </summary>
/// <param name="type">The <see cref="IType"/> the identifier should be.</param>
/// <param name="parms">An <see cref="IDictionary"/> of Param values that are keyed by parameter name.</param>
- /// <param name="d">The <see cref="Dialect.Dialect"/> to help with Configuration.</param>
- void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d);
+ /// <param name="dialect">The <see cref="Dialect.Dialect"/> to help with Configuration.</param>
+ void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect);
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/IPersistentIdentifierGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -53,7 +53,7 @@
/// <returns>
/// A <see cref="String"/> that will drop the database objects.
/// </returns>
- string SqlDropString(Dialect.Dialect dialect);
+ string[] SqlDropString(Dialect.Dialect dialect);
/// <summary>
/// Return a key unique to the underlying database objects.
Modified: trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/IncrementGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -38,8 +38,8 @@
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
- /// <param name="d"></param>
- public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect d)
+ /// <param name="dialect"></param>
+ public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
{
string tableList;
string column;
@@ -62,7 +62,7 @@
{
buf.Append("select ").Append(column).Append(" from ");
}
- buf.Append(d.Qualify(catalog, schema, tables[i]));
+ buf.Append(dialect.Qualify(catalog, schema, tables[i]));
if (i < tables.Length - 1)
buf.Append(" union ");
}
Modified: trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -4,7 +4,6 @@
using log4net;
using NHibernate.Engine;
using NHibernate.Exceptions;
-using NHibernate.Mapping;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Type;
@@ -157,9 +156,9 @@
/// <returns>
/// A <see cref="String"/> that will drop the database objects for the SequenceGenerator.
/// </returns>
- public string SqlDropString(Dialect.Dialect dialect)
+ public string[] SqlDropString(Dialect.Dialect dialect)
{
- return dialect.GetDropSequenceString(sequenceName);
+ return new string[] { dialect.GetDropSequenceString(sequenceName) };
}
/// <summary>
Modified: trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Id/TableGenerator.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -286,9 +286,9 @@
/// <returns>
/// A <see cref="string"/> that will drop the database objects for the TableGenerator.
/// </returns>
- public string SqlDropString(Dialect.Dialect dialect)
+ public string[] SqlDropString(Dialect.Dialect dialect)
{
- return dialect.GetDropTableString(tableName);
+ return new string[] { dialect.GetDropTableString(tableName) };
}
/// <summary>
Modified: trunk/nhibernate/src/NHibernate/Mapping/Table.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/Mapping/Table.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -1022,5 +1022,19 @@
{
throw new NotSupportedException();
}
+
+ public static string Qualify(string catalog, string schema, string table)
+ {
+ StringBuilder qualifiedName = new StringBuilder(100);
+ if (catalog != null)
+ {
+ qualifiedName.Append(catalog).Append('.');
+ }
+ if (schema != null)
+ {
+ qualifiedName.Append(schema).Append('.');
+ }
+ return qualifiedName.Append(table).ToString();
+ }
}
}
Modified: trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate/NHibernate-2.0.csproj 2008-08-15 21:41:48 UTC (rev 3706)
@@ -631,6 +631,9 @@
<Compile Include="Engine\Query\Sql\NativeSQLQueryRootReturn.cs" />
<Compile Include="Engine\Query\Sql\NativeSQLQueryScalarReturn.cs" />
<Compile Include="Engine\StatefulPersistenceContext.cs" />
+ <Compile Include="Engine\TransactionHelper.cs" />
+ <Compile Include="Engine\Transaction\IIsolatedWork.cs" />
+ <Compile Include="Engine\Transaction\Isolater.cs" />
<Compile Include="Engine\TwoPhaseLoad.cs" />
<Compile Include="Engine\ValueInclusion.cs" />
<Compile Include="Engine\VersionValue.cs" />
@@ -738,6 +741,13 @@
<Compile Include="Criterion\SqlFunctionProjection.cs" />
<Compile Include="FKUnmatchingColumnsException.cs" />
<Compile Include="Id\AbstractPostInsertGenerator.cs" />
+ <Compile Include="Id\Enhanced\IAccessCallback.cs" />
+ <Compile Include="Id\Enhanced\IDatabaseStructure.cs" />
+ <Compile Include="Id\Enhanced\IOptimizer.cs" />
+ <Compile Include="Id\Enhanced\OptimizerFactory.cs" />
+ <Compile Include="Id\Enhanced\SequenceStructure.cs" />
+ <Compile Include="Id\Enhanced\SequenceStyleGenerator.cs" />
+ <Compile Include="Id\Enhanced\TableStructure.cs" />
<Compile Include="Id\Insert\AbstractReturningDelegate.cs">
<SubType>Code</SubType>
</Compile>
Added: trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/IdGen/Enhanced/SequenceStyleConfigUnitFixture.cs 2008-08-15 21:41:48 UTC (rev 3706)
@@ -0,0 +1,172 @@
+using System.Collections.Generic;
+using NHibernate.Id.Enhanced;
+using NUnit.Framework;
+using NUnit.Framework.SyntaxHelpers;
+
+namespace NHibernate.Test.IdGen.Enhanced
+{
+ /// <summary>
+ /// Tests that SequenceStyleGenerator configures itself as expected in various scenarios
+ /// </summary>
+ [TestFixture]
+ public class SequenceStyleConfigUnitFixture
+ {
+ private class TableDialect : Dialect.Dialect
+ {
+ public override bool SupportsSequences
+ {
+ get { return false; }
+ }
+ }
+
+ private class SequenceDialect : Dialect.Dialect
+ {
+ public override bool SupportsSequences
+ {
+ get { return true; }
+ }
+
+ public override bool SupportsPooledSequences
+ {
+ get { return false; }
+ }
+
+ public override string GetSequenceNextValString(string sequenceName)
+ {
+ return string.Empty;
+ }
+ }
+
+ private class PooledSequenceDialect : SequenceDialect
+ {
+ public override bool SupportsPooledSequences
+ {
+ get { return true; }
+ }
+ }
+
+ // Test explicitly specifying both optimizer and increment
+ [Test]
+ public void ExplicitOptimizerWithExplicitIncrementSize()
+ {
+ // with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Dialect.Dialect dialect = new SequenceDialect();
+
+ // optimizer=none w/ increment > 1 => should honor optimizer
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.None;
+ props[SequenceStyleGenerator.IncrementParam] = "20";
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer)));
+ Assert.AreEqual(1, generator.Optimizer.IncrementSize);
+ Assert.AreEqual(1, generator.DatabaseStructure.IncrementSize);
+
+ // optimizer=hilo w/ increment > 1 => hilo
+ props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.HiLo;
+ props[SequenceStyleGenerator.IncrementParam] = "20";
+ generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer)));
+ Assert.AreEqual(20, generator.Optimizer.IncrementSize);
+ Assert.AreEqual(20, generator.DatabaseStructure.IncrementSize);
+
+ // optimizer=pooled w/ increment > 1 => hilo
+ props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.OptimizerParam] = OptimizerFactory.Pool;
+ props[SequenceStyleGenerator.IncrementParam] = "20";
+ generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer)));
+ Assert.AreEqual(20, generator.Optimizer.IncrementSize);
+ Assert.AreEqual(20, generator.DatabaseStructure.IncrementSize);
+ }
+
+ // Test all params defaulted with a dialect supporting sequences
+ [Test]
+ public void DefaultedSequenceBackedConfiguration()
+ {
+ Dialect.Dialect dialect = new SequenceDialect();
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+ }
+
+ // Test all params defaulted with a dialect which does not support sequences
+ [Test]
+ public void DefaultedTableBackedConfiguration()
+ {
+ Dialect.Dialect dialect = new TableDialect();
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+ }
+
+ //Test default optimizer selection for sequence backed generators
+ //based on the configured increment size; both in the case of the
+ //dialect supporting pooled sequences (pooled) and not (hilo)
+ [Test]
+ public void DefaultOptimizerBasedOnIncrementBackedBySequence()
+ {
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.IncrementParam] = "10";
+
+ // for dialects which do not support pooled sequences, we default to hilo
+ Dialect.Dialect dialect = new SequenceDialect();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.HiLoOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+
+ // for dialects which do support pooled sequences, we default to pooled
+ dialect = new PooledSequenceDialect();
+ generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (SequenceStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.PooledOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+ }
+
+ // Test default optimizer selection for table backed generators
+ // based on the configured increment size. Here we always prefer pooled.
+ [Test]
+ public void DefaultOptimizerBasedOnIncrementBackedByTable()
+ {
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.IncrementParam] = "10";
+ Dialect.Dialect dialect = new TableDialect();
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.PooledOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+ }
+
+ // Test forcing of table as backing strucuture with dialect supporting sequences
+ [Test]
+ public void ForceTableUse()
+ {
+ Dialect.Dialect dialect = new SequenceDialect();
+ IDictionary<string, string> props = new Dictionary<string, string>();
+ props[SequenceStyleGenerator.ForceTableParam] = "true";
+ SequenceStyleGenerator generator = new SequenceStyleGenerator();
+ generator.Configure(NHibernateUtil.Int64, props, dialect);
+ Assert.That(generator.DatabaseStructure, Is.AssignableFrom(typeof (TableStructure)));
+ Assert.That(generator.Optimizer, Is.AssignableFrom(typeof (OptimizerFactory.NoopOptimizer)));
+ Assert.That(generator.DatabaseStructure.Name, Is.EqualTo(SequenceStyleGenerator.DefaultSequenceName));
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 11:25:15 UTC (rev 3705)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-08-15 21:41:48 UTC (rev 3706)
@@ -226,6 +226,7 @@
<Compile Include="HQLFunctionTest\SQLFunctionTemplateTest.cs" />
<Compile Include="BulkManipulation\NativeSQLBulkOperations.cs" />
<Compile Include="BulkManipulation\Vehicles.cs" />
+ <Compile Include="IdGen\Enhanced\SequenceStyleConfigUnitFixture.cs" />
<Compile Include="IdTest\Car.cs" />
<Compile Include="IdTest\HiLoInt16Class.cs" />
<Compile Include="IdTest\HiLoInt32Class.cs" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|