diff --git a/src/NHibernate.Test/NHSpecificTest/NH3372/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3372/Entity.cs new file mode 100644 index 00000000000..5127f405983 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3372/Entity.cs @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.NH3372 +{ + public class Entity + { + public int Id { get; set; } + public string ShardId { get; set; } + public string Content { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3372/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3372/Fixture.cs new file mode 100644 index 00000000000..668c0085aaa --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3372/Fixture.cs @@ -0,0 +1,47 @@ +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3372 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return dialect is NHibernate.Dialect.MsSql2000Dialect; + } + + [Test] + public void CanGeneratePropertyOnInsertOfEntityWithCustomLoader() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var entity = new Entity { Content = "Some text" }; + session.Save(entity); + session.Flush(); + + Assert.That(entity.ShardId, Is.Not.Null & Has.Length.GreaterThan(0)); + } + } + + [Test] + public void CanGeneratePropertyOnUpdateOfEntityWithCustomLoader() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var entity = new Entity { Content = "Some text" }; + session.Save(entity); + session.Flush(); + + entity.ShardId = null; + entity.Content = "Some other text"; + session.Update(entity); + session.Flush(); + + Assert.That(entity.ShardId, Is.Not.Null & Has.Length.GreaterThan(0)); + } + } + + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3372/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH3372/Mappings.hbm.xml new file mode 100644 index 00000000000..5d4f58029e6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3372/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + SELECT id AS {e.Id} + , DB_NAME() AS {e.ShardId} + , content AS {e.Content} + FROM entity + WHERE id = ? + + \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3570/BiFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3570/BiFixture.cs index 6e75293c049..5222dbeabdc 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3570/BiFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3570/BiFixture.cs @@ -1,6 +1,5 @@ using System; using NUnit.Framework; -using SharpTestsEx; namespace NHibernate.Test.NHSpecificTest.NH3570 { @@ -29,8 +28,8 @@ public void ShouldNotSaveRemoveChild() { using (s.BeginTransaction()) { - s.Get(id).Children.Count.Should().Be.EqualTo(1); - s.CreateCriteria().List().Count.Should().Be.EqualTo(1); + Assert.That(s.Get(id).Children.Count, Is.EqualTo(1)); + Assert.That(s.CreateCriteria().List().Count, Is.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3570/UniFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3570/UniFixture.cs index 749eddbfe42..b366e65dc91 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3570/UniFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3570/UniFixture.cs @@ -1,6 +1,5 @@ using System; using NUnit.Framework; -using SharpTestsEx; namespace NHibernate.Test.NHSpecificTest.NH3570 { @@ -29,8 +28,8 @@ public void ShouldNotSaveRemoveChild() { using (s.BeginTransaction()) { - s.Get(id).Children.Count.Should().Be.EqualTo(1); - s.CreateCriteria().List().Count.Should().Be.EqualTo(1); + Assert.That(s.Get(id).Children.Count, Is.EqualTo(1)); + Assert.That(s.CreateCriteria().List().Count, Is.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index c60b89ab659..90cd4a138a0 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -691,6 +691,8 @@ + + @@ -3068,6 +3070,7 @@ + diff --git a/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs b/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs index bc4161a0a1a..f4b2218640f 100644 --- a/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs +++ b/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs @@ -6,7 +6,6 @@ using NHibernate.Mapping.ByCode.Conformist; using NHibernate.Linq; using NUnit.Framework; -using SharpTestsEx; namespace NHibernate.Test.Stateless.FetchingLazyCollections { @@ -138,13 +137,13 @@ public void ShouldWorkLoadingComplexEntities() Assert.That(hf.Count, Is.EqualTo(1)); Assert.That(hf[0].Father.Name, Is.EqualTo(humanFather)); Assert.That(hf[0].Mother.Name, Is.EqualTo(humanMother)); - NHibernateUtil.IsInitialized(hf[0].Childs).Should("Lazy collection should be initialized").Be.True(); + Assert.That(NHibernateUtil.IsInitialized(hf[0].Childs), Is.True, "Lazy collection should be initialized"); IList> rf = s.Query>().FetchMany(f => f.Childs).ToList(); Assert.That(rf.Count, Is.EqualTo(1)); Assert.That(rf[0].Father.Description, Is.EqualTo(crocodileFather)); Assert.That(rf[0].Mother.Description, Is.EqualTo(crocodileMother)); - NHibernateUtil.IsInitialized(hf[0].Childs).Should("Lazy collection should be initialized").Be.True(); + Assert.That(NHibernateUtil.IsInitialized(hf[0].Childs), Is.True, "Lazy collection should be initialized"); tx.Commit(); } diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 62ed069d4b2..9ac97831c39 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -4026,7 +4026,23 @@ public void ProcessInsertGeneratedProperties(object id, object entity, object[] { throw new AssertionFailure("no insert-generated properties"); } - ProcessGeneratedProperties(id, entity, state, session, sqlInsertGeneratedValuesSelectString, PropertyInsertGenerationInclusions); + + session.Batcher.ExecuteBatch(); //force immediate execution of the insert + + if (loaderName == null) + { + ProcessGeneratedPropertiesWithGeneratedSql(id, entity, state, session, sqlInsertGeneratedValuesSelectString, PropertyInsertGenerationInclusions); + } + else + { + ProcessGeneratedPropertiesWithLoader(id, entity, session); + + // The loader has added the entity to the first-level cache. We must remove + // the entity from the first-level cache to avoid problems in the Save or SaveOrUpdate + // event listeners, which don't expect the entity to already be present in the + // first-level cache. + session.PersistenceContext.RemoveEntity(session.GenerateEntityKey(id, this)); + } } public void ProcessUpdateGeneratedProperties(object id, object entity, object[] state, ISessionImplementor session) @@ -4035,14 +4051,25 @@ public void ProcessUpdateGeneratedProperties(object id, object entity, object[] { throw new AssertionFailure("no update-generated properties"); } - ProcessGeneratedProperties(id, entity, state, session, sqlUpdateGeneratedValuesSelectString, PropertyUpdateGenerationInclusions); + + session.Batcher.ExecuteBatch(); //force immediate execution of the update + + if (loaderName == null) + { + ProcessGeneratedPropertiesWithGeneratedSql(id, entity, state, session, sqlUpdateGeneratedValuesSelectString, PropertyUpdateGenerationInclusions); + } + else + { + // Remove entity from first-level cache to ensure that loader fetches fresh data from database. + // The loader will ensure that the same entity is added back to the first-level cache. + session.PersistenceContext.RemoveEntity(session.GenerateEntityKey(id, this)); + ProcessGeneratedPropertiesWithLoader(id, entity, session); + } } - private void ProcessGeneratedProperties(object id, object entity, object[] state, - ISessionImplementor session, SqlString selectionSQL, ValueInclusion[] includeds) + private void ProcessGeneratedPropertiesWithGeneratedSql(object id, object entity, object[] state, + ISessionImplementor session, SqlString selectionSQL, ValueInclusion[] generationInclusions) { - session.Batcher.ExecuteBatch(); //force immediate execution of the insert - using (new SessionIdLoggingContext(session.SessionId)) try { @@ -4060,7 +4087,7 @@ private void ProcessGeneratedProperties(object id, object entity, object[] state } for (int i = 0; i < PropertySpan; i++) { - if (includeds[i] != ValueInclusion.None) + if (generationInclusions[i] != ValueInclusion.None) { object hydratedState = PropertyTypes[i].Hydrate(rs, GetPropertyAliases(string.Empty, i), session, entity); state[i] = PropertyTypes[i].ResolveIdentifier(hydratedState, session, entity); @@ -4087,6 +4114,24 @@ private void ProcessGeneratedProperties(object id, object entity, object[] state } } + private void ProcessGeneratedPropertiesWithLoader(object id, object entity, ISessionImplementor session) + { + var query = (AbstractQueryImpl)session.GetNamedQuery(loaderName); + if (query.HasNamedParameters) + { + query.SetParameter(query.NamedParameters[0], id, this.IdentifierType); + } + else + { + query.SetParameter(0, id, this.IdentifierType); + } + query.SetOptionalId(id); + query.SetOptionalEntityName(this.EntityName); + query.SetOptionalObject(entity); + query.SetFlushMode(FlushMode.Never); + query.List(); + } + public bool HasSubselectLoadableCollections { get { return hasSubselectLoadableCollections; }