|
From: <fab...@us...> - 2008-11-04 12:08:39
|
Revision: 3888
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3888&view=rev
Author: fabiomaulo
Date: 2008-11-04 12:08:34 +0000 (Tue, 04 Nov 2008)
Log Message:
-----------
Fix NH-871 (new select generator)
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs
trunk/nhibernate/src/NHibernate/Id/Insert/AbstractSelectingDelegate.cs
trunk/nhibernate/src/NHibernate/NHibernate.csproj
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Id/SelectGenerator.cs
trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/
trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.cs
trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/SelectGeneratorTest.cs
Modified: trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs 2008-11-02 22:55:51 UTC (rev 3887)
+++ trunk/nhibernate/src/NHibernate/Id/IdentifierGeneratorFactory.cs 2008-11-04 12:08:34 UTC (rev 3888)
@@ -165,6 +165,7 @@
idgenerators.Add("foreign", typeof(ForeignGenerator));
idgenerators.Add("guid", typeof(GuidGenerator));
idgenerators.Add("guid.comb", typeof(GuidCombGenerator));
+ idgenerators.Add("select", typeof(SelectGenerator));
}
private IdentifierGeneratorFactory()
Modified: trunk/nhibernate/src/NHibernate/Id/Insert/AbstractSelectingDelegate.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/Insert/AbstractSelectingDelegate.cs 2008-11-02 22:55:51 UTC (rev 3887)
+++ trunk/nhibernate/src/NHibernate/Id/Insert/AbstractSelectingDelegate.cs 2008-11-04 12:08:34 UTC (rev 3888)
@@ -51,7 +51,7 @@
try
{
//fetch the generated id in a separate query
- IDbCommand idSelect = session.Batcher.PrepareCommand(CommandType.Text, selectSQL, SqlTypeFactory.NoTypes);
+ IDbCommand idSelect = session.Batcher.PrepareCommand(CommandType.Text, selectSQL, ParametersTypes);
try
{
BindParameters(session, idSelect, binder.Entity);
@@ -91,10 +91,22 @@
/// <returns> The generated identifier </returns>
protected internal abstract object GetResult(ISessionImplementor session, IDataReader rs, object entity);
- /// <summary> Bind any required parameter values into the SQL command {@link #getSelectSQL}. </summary>
+ /// <summary> Bind any required parameter values into the SQL command <see cref="SelectSQL"/>. </summary>
/// <param name="session">The session </param>
- /// <param name="ps">The prepared {@link #getSelectSQL SQL} command </param>
+ /// <param name="ps">The prepared <see cref="SelectSQL"/> command </param>
/// <param name="entity">The entity being saved. </param>
- protected internal virtual void BindParameters(ISessionImplementor session, IDbCommand ps, object entity) {}
+ protected internal virtual void BindParameters(ISessionImplementor session, IDbCommand ps, object entity) { }
+
+ #region NH Specific
+
+ /// <summary>
+ /// Types of any required parameter values into the SQL command <see cref="SelectSQL"/>.
+ /// </summary>
+ protected internal virtual SqlType[] ParametersTypes
+ {
+ get { return SqlTypeFactory.NoTypes; }
+ }
+
+ #endregion
}
}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate/Id/SelectGenerator.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Id/SelectGenerator.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Id/SelectGenerator.cs 2008-11-04 12:08:34 UTC (rev 3888)
@@ -0,0 +1,126 @@
+using System.Collections.Generic;
+using System.Data;
+using NHibernate.Engine;
+using NHibernate.Id.Insert;
+using NHibernate.Persister.Entity;
+using NHibernate.SqlCommand;
+using NHibernate.SqlTypes;
+using NHibernate.Type;
+
+namespace NHibernate.Id
+{
+ /// <summary>
+ /// A generator that selects the just inserted row to determine the identifier
+ /// value assigned by the database. The correct row is located using a unique key.
+ /// </summary>
+ /// <remarks>One mapping parameter is required: key (unless a natural-id is defined in the mapping).</remarks>
+ public class SelectGenerator : AbstractPostInsertGenerator, IConfigurable
+ {
+ private string uniqueKeyPropertyName;
+
+ #region Overrides of AbstractPostInsertGenerator
+
+ public override IInsertGeneratedIdentifierDelegate GetInsertGeneratedIdentifierDelegate(
+ IPostInsertIdentityPersister persister, ISessionFactoryImplementor factory, bool isGetGeneratedKeysEnabled)
+ {
+ return new SelectGeneratorDelegate(persister, factory, uniqueKeyPropertyName);
+ }
+
+ #endregion
+
+ #region Implementation of IConfigurable
+
+ public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
+ {
+ parms.TryGetValue("key", out uniqueKeyPropertyName);
+ }
+
+ #endregion
+
+ private static string DetermineNameOfPropertyToUse(IEntityPersister persister, string supplied)
+ {
+ if (supplied != null)
+ {
+ return supplied;
+ }
+ int[] naturalIdPropertyIndices = persister.NaturalIdentifierProperties;
+ if (naturalIdPropertyIndices == null)
+ {
+ throw new IdentifierGenerationException("no natural-id property defined; need to specify [key] in "
+ + "generator parameters");
+ }
+ if (naturalIdPropertyIndices.Length > 1)
+ {
+ throw new IdentifierGenerationException("select generator does not currently support composite "
+ + "natural-id properties; need to specify [key] in generator parameters");
+ }
+ ValueInclusion inclusion = persister.PropertyInsertGenerationInclusions[naturalIdPropertyIndices[0]];
+ if (inclusion != ValueInclusion.None)
+ {
+ throw new IdentifierGenerationException("natural-id also defined as insert-generated; need to specify [key] "
+ + "in generator parameters");
+ }
+ return persister.PropertyNames[naturalIdPropertyIndices[0]];
+ }
+
+ #region Nested type: SelectGeneratorDelegate
+
+ /// <summary> The delegate for the select generation strategy.</summary>
+ public class SelectGeneratorDelegate : AbstractSelectingDelegate
+ {
+ private readonly ISessionFactoryImplementor factory;
+ private readonly SqlString idSelectString;
+ private readonly IType idType;
+ private readonly IPostInsertIdentityPersister persister;
+
+ private readonly string uniqueKeyPropertyName;
+ private readonly IType uniqueKeyType;
+
+ internal SelectGeneratorDelegate(IPostInsertIdentityPersister persister, ISessionFactoryImplementor factory,
+ string suppliedUniqueKeyPropertyName) : base(persister)
+ {
+ this.persister = persister;
+ this.factory = factory;
+ uniqueKeyPropertyName = DetermineNameOfPropertyToUse((IEntityPersister) persister, suppliedUniqueKeyPropertyName);
+
+ idSelectString = persister.GetSelectByUniqueKeyString(uniqueKeyPropertyName);
+ uniqueKeyType = ((IEntityPersister) persister).GetPropertyType(uniqueKeyPropertyName);
+ idType = persister.IdentifierType;
+ }
+
+ protected internal override SqlString SelectSQL
+ {
+ get { return idSelectString; }
+ }
+
+ protected internal override SqlType[] ParametersTypes
+ {
+ get { return uniqueKeyType.SqlTypes(factory); }
+ }
+
+ public override IdentifierGeneratingInsert PrepareIdentifierGeneratingInsert()
+ {
+ return new IdentifierGeneratingInsert(factory);
+ }
+
+ protected internal override void BindParameters(ISessionImplementor session, IDbCommand ps, object entity)
+ {
+ object uniqueKeyValue = ((IEntityPersister) persister).GetPropertyValue(entity, uniqueKeyPropertyName,
+ session.EntityMode);
+ uniqueKeyType.NullSafeSet(ps, uniqueKeyValue, 0, session);
+ }
+
+ protected internal override object GetResult(ISessionImplementor session, IDataReader rs, object entity)
+ {
+ if (!rs.Read())
+ {
+ throw new IdentifierGenerationException("the inserted row could not be located by the unique key: "
+ + uniqueKeyPropertyName);
+ }
+ return idType.NullSafeGet(rs, persister.RootTableKeyColumnNames, session, entity);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-11-02 22:55:51 UTC (rev 3887)
+++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-11-04 12:08:34 UTC (rev 3888)
@@ -440,6 +440,7 @@
<Compile Include="AdoNet\ResultSetWrapper.cs" />
<Compile Include="AdoNet\SqlClientBatchingBatcherFactory.cs" />
<Compile Include="AdoNet\TooManyRowsAffectedException.cs" />
+ <Compile Include="Id\SelectGenerator.cs" />
<Compile Include="Properties\BackFieldStrategy.cs" />
<Compile Include="Bytecode\CodeDom\BytecodeProviderImpl.cs" />
<Compile Include="Bytecode\IAccessOptimizer.cs" />
Added: trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.cs 2008-11-04 12:08:34 UTC (rev 3888)
@@ -0,0 +1,25 @@
+namespace NHibernate.Test.Generatedkeys.Select
+{
+ public class MyEntity
+ {
+ private int id;
+ private string name;
+ protected MyEntity() {}
+
+ public MyEntity(string name)
+ {
+ this.name = name;
+ }
+
+ public virtual int Id
+ {
+ get { return id; }
+ }
+
+ public virtual string Name
+ {
+ get { return name; }
+ set { name = value; }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/MyEntity.hbm.xml 2008-11-04 12:08:34 UTC (rev 3888)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Generatedkeys.Select"
+ default-access="field">
+
+ <class name="MyEntity" table="my_entity">
+
+ <id name="id">
+ <generator class="select"/>
+ </id>
+ <natural-id>
+ <property name="name"/>
+ </natural-id>
+ </class>
+
+ <database-object>
+ <create>
+CREATE GENERATOR MYGENERATOR;
+ </create>
+ <drop>
+DROP GENERATOR MYGENERATOR;
+ </drop>
+ <dialect-scope name="NHibernate.Dialect.FirebirdDialect"/>
+ </database-object>
+
+ <database-object>
+ <create>
+CREATE TRIGGER my_entity_BI FOR my_entity
+ACTIVE BEFORE INSERT
+POSITION 0
+AS
+BEGIN
+NEW.ID = GEN_ID (MYGENERATOR, 1);
+END
+ </create>
+ <drop>
+DROP TRIGGER my_entity_BI;
+ </drop>
+ <dialect-scope name="NHibernate.Dialect.FirebirdDialect"/>
+ </database-object>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/SelectGeneratorTest.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/SelectGeneratorTest.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Generatedkeys/Select/SelectGeneratorTest.cs 2008-11-04 12:08:34 UTC (rev 3888)
@@ -0,0 +1,42 @@
+using System.Collections;
+using NUnit.Framework;
+
+namespace NHibernate.Test.Generatedkeys.Select
+{
+ [TestFixture]
+ public class SelectGeneratorTest: TestCase
+ {
+ protected override IList Mappings
+ {
+ get { return new[] { "Generatedkeys.Select.MyEntity.hbm.xml" }; }
+ }
+
+ protected override string MappingsAssembly
+ {
+ get { return "NHibernate.Test"; }
+ }
+
+ protected override bool AppliesTo(Dialect.Dialect dialect)
+ {
+ return dialect is Dialect.FirebirdDialect;
+ }
+
+ [Test]
+ public void GetGeneratedKeysSupport()
+ {
+ ISession session = OpenSession();
+ session.BeginTransaction();
+
+ MyEntity e = new MyEntity("entity-1");
+ session.Save(e);
+
+ // this insert should happen immediately!
+ Assert.AreEqual(1, e.Id, "id not generated through forced insertion");
+
+ session.Delete(e);
+ session.Transaction.Commit();
+ session.Close();
+ }
+
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-02 22:55:51 UTC (rev 3887)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-04 12:08:34 UTC (rev 3888)
@@ -243,6 +243,8 @@
<Compile Include="Generatedkeys\Identity\MyChild.cs" />
<Compile Include="Generatedkeys\Identity\MyEntity.cs" />
<Compile Include="Generatedkeys\Identity\MySibling.cs" />
+ <Compile Include="Generatedkeys\Select\MyEntity.cs" />
+ <Compile Include="Generatedkeys\Select\SelectGeneratorTest.cs" />
<Compile Include="GeneratedTest\AbstractGeneratedPropertyTest.cs" />
<Compile Include="GeneratedTest\Component.cs" />
<Compile Include="GeneratedTest\ComponentOwner.cs" />
@@ -1515,6 +1517,7 @@
<EmbeddedResource Include="Cascade\JobBatch.hbm.xml" />
<EmbeddedResource Include="Deletetransient\Person.hbm.xml" />
<Content Include="DynamicEntity\package.html" />
+ <EmbeddedResource Include="Generatedkeys\Select\MyEntity.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1478\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1447\Mappings.hbm.xml" />
<EmbeddedResource Include="TypesTest\EnumCharClass.hbm.xml" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|