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. |