|
From: <fab...@us...> - 2009-02-06 20:28:20
|
Revision: 4062
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4062&view=rev
Author: fabiomaulo
Date: 2009-02-06 20:28:16 +0000 (Fri, 06 Feb 2009)
Log Message:
-----------
Fix NH-1662 (new feature sequence-identity tested and supported by Oracle)
Possible breaking change:
see IDriver
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs
trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs
trunk/nhibernate/src/NHibernate/Driver/IDriver.cs
trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs
trunk/nhibernate/src/NHibernate/Id/Insert/AbstractReturningDelegate.cs
trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs
trunk/nhibernate/src/NHibernate/NHibernate.csproj
trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Seqidentity/SequenceIdentityFixture.cs
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Id/Insert/OutputParamReturningDelegate.cs
trunk/nhibernate/src/NHibernate/Id/Insert/ReturningIdentifierInsert.cs
trunk/nhibernate/src/NHibernate/Id/SequenceIdentityGenerator.cs
Modified: trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Dialect/Dialect.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -2061,5 +2061,14 @@
return null;
}
}
+
+ #region NH specific
+
+ public virtual SqlString AddIdentifierOutParameterToInsert(SqlString insertString, string identifierColumnName, string parameterName)
+ {
+ return insertString;
+ }
+
+ #endregion
}
}
Modified: trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Dialect/Oracle8iDialect.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -329,6 +329,11 @@
return sequenceName + ".nextval";
}
+ public override SqlString AddIdentifierOutParameterToInsert(SqlString insertString, string identifierColumnName, string parameterName)
+ {
+ return insertString.Append(" returning " + identifierColumnName + " into :" + parameterName);
+ }
+
public override string GetCreateSequenceString(string sequenceName)
{
return "create sequence " + sequenceName; //starts with 1, implicitly
Modified: trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Driver/DriverBase.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -200,7 +200,7 @@
/// <param name="name">The name to set for IDbDataParameter.Name</param>
/// <param name="sqlType">The SqlType to set for IDbDataParameter.</param>
/// <returns>An IDbDataParameter ready to be added to an IDbCommand.</returns>
- protected IDbDataParameter GenerateParameter(IDbCommand command, string name, SqlType sqlType)
+ public IDbDataParameter GenerateParameter(IDbCommand command, string name, SqlType sqlType)
{
IDbDataParameter dbParam = command.CreateParameter();
InitializeParameter(dbParam, name, sqlType);
Modified: trunk/nhibernate/src/NHibernate/Driver/IDriver.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Driver/IDriver.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -85,5 +85,15 @@
/// </summary>
/// <param name="command"></param>
void PrepareCommand(IDbCommand command);
+
+ /// <summary>
+ /// Generates an IDbDataParameter for the IDbCommand. It does not add the IDbDataParameter to the IDbCommand's
+ /// Parameter collection.
+ /// </summary>
+ /// <param name="command">The IDbCommand to use to create the IDbDataParameter.</param>
+ /// <param name="name">The name to set for IDbDataParameter.Name</param>
+ /// <param name="sqlType">The SqlType to set for IDbDataParameter.</param>
+ /// <returns>An IDbDataParameter ready to be added to an IDbCommand.</returns>
+ IDbDataParameter GenerateParameter(IDbCommand command, string name, SqlType sqlType);
}
}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -171,6 +171,7 @@
idgenerators.Add("guid.comb", typeof(GuidCombGenerator));
idgenerators.Add("guid.native", typeof(NativeGuidGenerator));
idgenerators.Add("select", typeof(SelectGenerator));
+ idgenerators.Add("sequence-identity", typeof(SequenceIdentityGenerator));
}
private IdentifierGeneratorFactory()
Modified: trunk/nhibernate/src/NHibernate/Id/Insert/AbstractReturningDelegate.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Insert/AbstractReturningDelegate.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Id/Insert/AbstractReturningDelegate.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -21,7 +21,7 @@
this.persister = persister;
}
- protected internal virtual IPostInsertIdentityPersister Persister
+ protected IPostInsertIdentityPersister Persister
{
get { return persister; }
}
Added: trunk/nhibernate/src/NHibernate/Id/Insert/OutputParamReturningDelegate.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Insert/OutputParamReturningDelegate.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Insert/OutputParamReturningDelegate.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -0,0 +1,62 @@
+using System.Data;
+using NHibernate.Engine;
+using NHibernate.SqlCommand;
+using NHibernate.SqlTypes;
+
+namespace NHibernate.Id.Insert
+{
+ /// <summary>
+ /// <see cref="IInsertGeneratedIdentifierDelegate"/> implementation where the
+ /// underlying strategy causes the generated identitifer to be returned, as an
+ /// effect of performing the insert statement, in a Output parameter.
+ /// Thus, there is no need for an additional sql statement to determine the generated identitifer.
+ /// </summary>
+ public class OutputParamReturningDelegate : AbstractReturningDelegate
+ {
+ private const string ReturnParameterName = "nhIdOutParam";
+ private readonly ISessionFactoryImplementor factory;
+ private readonly string idColumnName;
+ private readonly SqlType paramType;
+ private string driveGeneratedParamName = ReturnParameterName;
+
+ public OutputParamReturningDelegate(IPostInsertIdentityPersister persister, ISessionFactoryImplementor factory)
+ : base(persister)
+ {
+ if (Persister.RootTableKeyColumnNames.Length > 1)
+ {
+ throw new HibernateException("identity-style generator cannot be used with multi-column keys");
+ }
+ paramType = Persister.IdentifierType.SqlTypes(factory)[0];
+ idColumnName = Persister.RootTableKeyColumnNames[0];
+ this.factory = factory;
+ }
+
+ #region Overrides of AbstractReturningDelegate
+
+ public override IdentifierGeneratingInsert PrepareIdentifierGeneratingInsert()
+ {
+ return new ReturningIdentifierInsert(factory, idColumnName, ReturnParameterName);
+ }
+
+ protected internal override IDbCommand Prepare(SqlCommandInfo insertSQL, ISessionImplementor session)
+ {
+ IDbCommand command = session.Batcher.PrepareCommand(CommandType.Text, insertSQL.Text, insertSQL.ParameterTypes);
+ //Add the output parameter
+ IDbDataParameter idParameter = factory.ConnectionProvider.Driver.GenerateParameter(command, ReturnParameterName,
+ paramType);
+ driveGeneratedParamName = idParameter.ParameterName;
+ idParameter.Direction = ParameterDirection.ReturnValue;
+
+ command.Parameters.Add(idParameter);
+ return command;
+ }
+
+ public override object ExecuteAndExtract(IDbCommand insert, ISessionImplementor session)
+ {
+ session.Batcher.ExecuteNonQuery(insert);
+ return ((IDbDataParameter)insert.Parameters[driveGeneratedParamName]).Value;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/Insert/ReturningIdentifierInsert.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Insert/ReturningIdentifierInsert.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/Insert/ReturningIdentifierInsert.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -0,0 +1,30 @@
+using NHibernate.Engine;
+using NHibernate.SqlCommand;
+
+namespace NHibernate.Id.Insert
+{
+ /// <summary>
+ /// Specialized IdentifierGeneratingInsert which appends the database
+ /// specific clause which signifies to return generated identifier values
+ /// to the end of the insert statement.
+ /// </summary>
+ /// <remarks>
+ /// </remarks>
+ public class ReturningIdentifierInsert : NoCommentsInsert
+ {
+ private readonly string identifierColumnName;
+ private readonly string returnParameterName;
+
+ public ReturningIdentifierInsert(ISessionFactoryImplementor factory, string identifierColumnName,
+ string returnParameterName) : base(factory)
+ {
+ this.returnParameterName = returnParameterName;
+ this.identifierColumnName = identifierColumnName;
+ }
+
+ public override SqlString ToSqlString()
+ {
+ return Dialect.AddIdentifierOutParameterToInsert(base.ToSqlString(), identifierColumnName, returnParameterName);
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/Id/SequenceGenerator.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -52,6 +52,11 @@
private SqlString sql;
private string parameters;
+ public string SequenceName
+ {
+ get { return sequenceName; }
+ }
+
#region IConfigurable Members
/// <summary>
Added: trunk/nhibernate/src/NHibernate/Id/SequenceIdentityGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/SequenceIdentityGenerator.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/SequenceIdentityGenerator.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -0,0 +1,55 @@
+using NHibernate.Engine;
+using NHibernate.Id.Insert;
+
+namespace NHibernate.Id
+{
+ /// <summary>
+ /// A generator which combines sequence generation with immediate retrieval
+ /// by attaching a output parameter to the SQL command
+ /// In this respect it works much like ANSI-SQL IDENTITY generation.
+ /// </summary>
+ public class SequenceIdentityGenerator : SequenceGenerator, IPostInsertIdentifierGenerator
+ {
+ #region IPostInsertIdentifierGenerator Members
+
+ public override object Generate(ISessionImplementor session, object obj)
+ {
+ return IdentifierGeneratorFactory.PostInsertIndicator;
+ }
+
+ #endregion
+
+ #region Implementation of IPostInsertIdentifierGenerator
+
+ public IInsertGeneratedIdentifierDelegate GetInsertGeneratedIdentifierDelegate(IPostInsertIdentityPersister persister,
+ ISessionFactoryImplementor factory,
+ bool isGetGeneratedKeysEnabled)
+ {
+ return new SequenceIdentityDelegate(persister, factory, SequenceName);
+ }
+
+ #endregion
+
+ #region Nested type: SequenceIdentityDelegate
+
+ public class SequenceIdentityDelegate : OutputParamReturningDelegate
+ {
+ private readonly string sequenceNextValFragment;
+
+ public SequenceIdentityDelegate(IPostInsertIdentityPersister persister, ISessionFactoryImplementor factory,
+ string sequenceName) : base(persister, factory)
+ {
+ sequenceNextValFragment = factory.Dialect.GetSelectSequenceNextValString(sequenceName);
+ }
+
+ public override IdentifierGeneratingInsert PrepareIdentifierGeneratingInsert()
+ {
+ IdentifierGeneratingInsert insert = base.PrepareIdentifierGeneratingInsert();
+ insert.AddColumn(Persister.RootTableKeyColumnNames[0], sequenceNextValFragment);
+ return insert;
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-02-06 20:28:16 UTC (rev 4062)
@@ -465,8 +465,11 @@
<Compile Include="Exceptions\SqlStateExtracter.cs" />
<Compile Include="Exceptions\TemplatedViolatedConstraintNameExtracter.cs" />
<Compile Include="Id\Insert\NoCommentsInsert.cs" />
+ <Compile Include="Id\Insert\ReturningIdentifierInsert.cs" />
+ <Compile Include="Id\Insert\OutputParamReturningDelegate.cs" />
<Compile Include="Id\NativeGuidGenerator.cs" />
<Compile Include="Id\SelectGenerator.cs" />
+ <Compile Include="Id\SequenceIdentityGenerator.cs" />
<Compile Include="IFutureValue.cs" />
<Compile Include="Impl\DelayedEnumerator.cs" />
<Compile Include="Impl\FutureQueryBatch.cs" />
Modified: trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Seqidentity/SequenceIdentityFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Seqidentity/SequenceIdentityFixture.cs 2009-02-06 18:25:52 UTC (rev 4061)
+++ trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Seqidentity/SequenceIdentityFixture.cs 2009-02-06 20:28:16 UTC (rev 4062)
@@ -3,7 +3,7 @@
namespace NHibernate.Test.Generatedkeys.Seqidentity
{
- [TestFixture, Ignore("Solution not implemented yet.")]
+ [TestFixture]
public class SequenceIdentityFixture : TestCase
{
protected override IList Mappings
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|