|
From: <fab...@us...> - 2008-10-09 18:19:10
|
Revision: 3818
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3818&view=rev
Author: fabiomaulo
Date: 2008-10-09 18:19:03 +0000 (Thu, 09 Oct 2008)
Log Message:
-----------
Fix NH-727
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate.Test/SqlTest/IdentityInsertWithStoredProcsTest.cs
trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcs.hbm.xml
trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcsTest.cs
Modified: trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2008-10-09 16:41:52 UTC (rev 3817)
+++ trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2008-10-09 18:19:03 UTC (rev 3818)
@@ -3300,10 +3300,10 @@
if (IsIdentifierAssignedByInsert)
{
identityDelegate = ((IPostInsertIdentifierGenerator)IdentifierGenerator).GetInsertGeneratedIdentifierDelegate(this, Factory, UseGetGeneratedKeys());
- SqlCommandInfo defaultInsert = GenerateInsertString(PropertyInsertability, 0);
+ SqlCommandInfo defaultInsert = GenerateIdentityInsertString(PropertyInsertability);
sqlIdentityInsertString = customSQLInsert[0] != null
? new SqlCommandInfo(customSQLInsert[0], defaultInsert.ParameterTypes)
- : GenerateIdentityInsertString(PropertyInsertability);
+ : defaultInsert;
}
else
{
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-10-09 16:41:52 UTC (rev 3817)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-10-09 18:19:03 UTC (rev 3818)
@@ -804,9 +804,11 @@
<Compile Include="SqlTest\FireBirdTest.cs" />
<Compile Include="SqlTest\GeneralTest.cs" />
<Compile Include="SqlTest\HandSQLTest.cs" />
+ <Compile Include="SqlTest\IdentityInsertWithStoredProcsTest.cs" />
<Compile Include="SqlTest\Item.cs" />
<Compile Include="SqlTest\MonetaryAmount.cs" />
<Compile Include="SqlTest\MonetaryAmountUserType.cs" />
+ <Compile Include="SqlTest\MSSQLIdentityInsertWithStoredProcsTest.cs" />
<Compile Include="SqlTest\MSSQLTest.cs" />
<Compile Include="SqlTest\NullDateUserType.cs" />
<Compile Include="SqlTest\Order.cs" />
@@ -1485,6 +1487,7 @@
<EmbeddedResource Include="Cascade\JobBatch.hbm.xml" />
<EmbeddedResource Include="Deletetransient\Person.hbm.xml" />
<Content Include="DynamicEntity\package.html" />
+ <EmbeddedResource Include="SqlTest\MSSQLIdentityInsertWithStoredProcs.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1508\Mappings.hbm.xml" />
<EmbeddedResource Include="GenericTest\OrderedSetGeneric\OrderedSetFixture.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1293\Mappings.hbm.xml" />
Added: trunk/nhibernate/src/NHibernate.Test/SqlTest/IdentityInsertWithStoredProcsTest.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/IdentityInsertWithStoredProcsTest.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/IdentityInsertWithStoredProcsTest.cs 2008-10-09 18:19:03 UTC (rev 3818)
@@ -0,0 +1,68 @@
+using NHibernate.Cfg;
+using NUnit.Framework;
+
+namespace NHibernate.Test.SqlTest
+{
+ public abstract class IdentityInsertWithStoredProcsTest : TestCase
+ {
+ protected override string MappingsAssembly
+ {
+ get { return "NHibernate.Test"; }
+ }
+
+ protected abstract string GetExpectedInsertOrgLogStatement(string orgName);
+
+ /// <summary>
+ /// Organization should be mappend with "identity" id strategy AND custom sql-insert (a stored proc).
+ /// The insert stored proc will return the new primary key and NH should recognize it and apply it
+ /// just like a normal insert.
+ /// </summary>
+ [Test]
+ public void InsertUsesStoredProc()
+ {
+ using (var spy = new SqlLogSpy())
+ {
+ Organization ifa;
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ ifa = new Organization("IFA");
+ s.Save(ifa);
+ t.Commit();
+ }
+
+ Assert.AreEqual(1, spy.Appender.GetEvents().Length, "Num loggedEvents");
+ Assert.AreEqual(1, ifa.Id, "ifa.Id");
+ Assert.AreEqual(GetExpectedInsertOrgLogStatement("IFA"), spy.Appender.GetEvents()[0].MessageObject, "Message 1");
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Delete(ifa);
+ t.Commit();
+ }
+ }
+
+ using (var spy = new SqlLogSpy())
+ {
+ Organization efa;
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ efa = new Organization("EFA");
+ s.Save(efa);
+ t.Commit();
+ }
+
+ Assert.AreEqual(1, spy.Appender.GetEvents().Length, "Num loggedEvents");
+ Assert.AreEqual(2, efa.Id, "efa.Id");
+ Assert.AreEqual(GetExpectedInsertOrgLogStatement("EFA"), spy.Appender.GetEvents()[0].MessageObject, "Message 2");
+ using (ISession s = OpenSession())
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Delete(efa);
+ t.Commit();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcs.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcs.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcs.hbm.xml 2008-10-09 18:19:03 UTC (rev 3818)
@@ -0,0 +1,201 @@
+<?xml version="1.0"?>
+<!--
+
+ This mapping demonstrates the use of Hibernate with
+ all-handwritten SQL!
+
+ This version is for Sybase/mssql
+-->
+<hibernate-mapping
+ xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.SqlTest"
+ default-access="field.camelcase">
+
+ <class name="Organization" table="ORGANIZATION">
+ <id name="Id" unsaved-value="0" column="ORGID">
+ <generator class="identity"/>
+ </id>
+ <property name="Name" not-null="true" column="NAME"/>
+ <set name="Employments"
+ inverse="true"
+ order-by="DUMMY">
+ <key column="EMPLOYER"/>
+ <!-- only needed for DDL generation -->
+ <one-to-many class="Employment"/>
+ <loader query-ref="organizationEmployments"/>
+ </set>
+ <!-- query-list name="currentEmployments"
+ query-ref="organizationCurrentEmployments"-->
+ <loader query-ref="organization"/>
+ <sql-insert>exec nh_organization_native_id_insert ?</sql-insert>
+ <sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ORGID=?</sql-update>
+ <sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
+ </class>
+
+ <class name="Person" table="PERSON">
+ <id name="Id" unsaved-value="0" column="PERID">
+ <generator class="increment"/>
+ </id>
+ <property name="Name" not-null="true" column="NAME"/>
+ <loader query-ref="person"/>
+ <sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(?), ? )</sql-insert>
+ <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
+ <sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
+ </class>
+
+ <class name="Employment" table="EMPLOYMENT">
+ <id name="employmentId" unsaved-value="0" column="EMPID">
+ <generator class="increment"/>
+ </id>
+ <many-to-one name="Employee" column="EMPLOYEE" not-null="true" update="false"/>
+ <many-to-one name="Employer" column="EMPLOYER" not-null="true" update="false"/>
+ <property name="StartDate" column="STARTDATE" not-null="true" update="false" insert="false"/>
+ <property name="EndDate" column="ENDDATE" insert="false" type="NHibernate.Test.SqlTest.NullDateUserType, NHibernate.Test"/>
+ <property name="RegionCode" column="REGIONCODE" update="false"/>
+ <property name="Salary" type="NHibernate.Test.SqlTest.MonetaryAmountUserType, NHibernate.Test">
+ <column name="VALUE" sql-type="float"/>
+ <column name="CURRENCY"/>
+ </property>
+ <loader query-ref="employment"/>
+ <sql-insert>
+ INSERT INTO EMPLOYMENT
+ (EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID)
+ VALUES (?, ?, getdate(), UPPER(?), ?, ?, ?)
+ </sql-insert>
+ <sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update>
+ <sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
+ </class>
+
+ <resultset name="org-emp-regionCode">
+ <return-scalar column="regionCode" type="string"/>
+ <return alias="org" class="Organization"/>
+ <return-join alias="emp" property="org.Employments"/>
+ </resultset>
+
+ <resultset name="org-emp-person">
+ <return alias="org" class="Organization"/>
+ <return-join alias="emp" property="org.Employments"/>
+ <return-join alias="pers" property="emp.Employee"/>
+ </resultset>
+
+ <sql-query name="person">
+ <return alias="p" class="Person" lock-mode="upgrade"/>
+ SELECT NAME AS {p.Name}, PERID AS {p.Id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
+ </sql-query>
+
+ <sql-query name="organization">
+ <return alias="org" class="Organization"/>
+ <return-join alias="emp" property="org.Employments"/>
+ SELECT {org.*}, {emp.*}
+ FROM ORGANIZATION org
+ LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+ WHERE org.ORGID=?
+ </sql-query>
+
+
+ <!--sql-query name="organization">
+ <return alias="org" class="Organization"/>
+ SELECT NAME AS {org.name}, ORGID AS {org.id} FROM ORGANIZATION
+ WHERE ORGID=?
+ </sql-query-->
+
+ <sql-query name="allOrganizationsWithEmployees" flush-mode="never">
+ <return alias="org" class="Organization"/>
+ SELECT DISTINCT org.NAME AS {org.Name}, org.ORGID AS {org.Id}
+ FROM ORGANIZATION org
+ INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
+ </sql-query>
+
+ <sql-query name="employment">
+ <return alias="emp" class="Employment"/>
+ SELECT EMPLOYEE AS {emp.Employee}, EMPLOYER AS {emp.Employer},
+ STARTDATE AS {emp.StartDate}, ENDDATE AS {emp.EndDate},
+ REGIONCODE as {emp.RegionCode}, EMPID AS {emp.Id}
+ FROM EMPLOYMENT
+ WHERE EMPID = ?
+ </sql-query>
+
+ <sql-query name="organizationEmployments">
+ <load-collection alias="empcol" role="Organization.Employments"/>
+ SELECT {empcol.*}
+ FROM EMPLOYMENT empcol
+ WHERE EMPLOYER = :id
+ ORDER BY STARTDATE ASC, EMPLOYEE ASC
+ </sql-query>
+
+
+ <sql-query name="organizationCurrentEmployments">
+ <return alias="emp" class="Employment">
+ <return-property name="Salary">
+ <!-- as multi column properties are not supported via the
+ {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ <!-- Here we are remapping endDate. Notice that we can still use {emp.EndDate} in the SQL. -->
+ <return-property name="EndDate" column="myEndDate"/>
+ </return>
+ <synchronize table="EMPLOYMENT"/>
+ SELECT EMPLOYEE AS {emp.Employee}, EMPLOYER AS {emp.Employer},
+ STARTDATE AS {emp.StartDate}, ENDDATE AS {emp.EndDate},
+ REGIONCODE as {emp.RegionCode}, EMPID AS {emp.Id}, VALUE, CURRENCY
+ FROM EMPLOYMENT
+ WHERE EMPLOYER = :id AND ENDDATE IS NULL
+ ORDER BY STARTDATE ASC
+ </sql-query>
+
+ <sql-query name="simpleScalar">
+ <return-scalar column="name" type="string"/>
+ <return-scalar column="value" type="long"/>
+ exec simpleScalar :number
+ </sql-query>
+
+ <sql-query name="paramhandling">
+ <return-scalar column="value" type="long"/>
+ <return-scalar column="value2" type="long"/>
+ exec paramHandling ?, ?
+ </sql-query>
+
+ <sql-query name="paramhandling_mixed">
+ <return-scalar column="value" type="long" />
+ <return-scalar column="value2" type="long" />
+ exec paramHandling ?, :second
+ </sql-query>
+
+ <sql-query name="selectAllEmployments">
+ <return class="Employment">
+ <return-property name="Employee" column="EMPLOYEE"/>
+ <return-property name="Employer" column="EMPLOYER"/>
+ <return-property name="StartDate" column="STARTDATE"/>
+ <return-property name="EndDate" column="ENDDATE"/>
+ <return-property name="RegionCode" column="REGIONCODE"/>
+ <return-property name="id" column="EMPID"/>
+ <return-property name="Salary">
+ <!-- as multi column properties are not supported via the
+ {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
+ exec selectAllEmployments
+ </sql-query>
+
+ <database-object>
+ <create>
+ CREATE PROCEDURE nh_organization_native_id_insert
+ (
+ @NAME as varchar
+ )
+ AS
+ BEGIN
+ INSERT INTO organization(NAME) VALUES(@NAME)
+ SELECT SCOPE_IDENTITY()
+ END
+ </create>
+ <drop>
+ IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'dbo.nh_organization_native_id_insert') AND OBJECTPROPERTY(id, N'IsProcedure') = 1)
+ DROP PROCEDURE dbo.nh_organization_native_id_insert
+ </drop>
+ </database-object>
+</hibernate-mapping>
Added: trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcsTest.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcsTest.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/SqlTest/MSSQLIdentityInsertWithStoredProcsTest.cs 2008-10-09 18:19:03 UTC (rev 3818)
@@ -0,0 +1,25 @@
+using System.Collections;
+using NHibernate.Dialect;
+using NUnit.Framework;
+
+namespace NHibernate.Test.SqlTest
+{
+ [TestFixture]
+ public class MSSQLIdentityInsertWithStoredProcsTest : IdentityInsertWithStoredProcsTest
+ {
+ protected override bool AppliesTo(Dialect.Dialect dialect)
+ {
+ return dialect is MsSql2000Dialect || dialect is MsSql2005Dialect;
+ }
+
+ protected override string GetExpectedInsertOrgLogStatement(string orgName)
+ {
+ return string.Format("exec nh_organization_native_id_insert @p0; @p0 = '{0}'", orgName);
+ }
+
+ protected override IList Mappings
+ {
+ get { return new[] {"SqlTest.MSSQLIdentityInsertWithStoredProcs.hbm.xml"}; }
+ }
+ }
+}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|