From: <fab...@us...> - 2010-09-26 16:54:22
|
Revision: 5224 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5224&view=rev Author: fabiomaulo Date: 2010-09-26 16:54:16 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Fix NH-2348 (thanks to Patrick Earl for the idea) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/ trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Domain.cs trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/PolymorphicGetAndLoadTest.cs Modified: trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs 2010-09-26 14:26:22 UTC (rev 5223) +++ trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs 2010-09-26 16:54:16 UTC (rev 5224) @@ -1,6 +1,6 @@ using System; using System.Diagnostics; - +using System.Text; using NHibernate.Cache; using NHibernate.Cache.Access; using NHibernate.Cache.Entry; @@ -36,7 +36,7 @@ } else { - persister = source.Factory.GetEntityPersister(@event.EntityClassName); + persister = GetEntityPersister(source.Factory, @event.EntityClassName); } if (persister == null) @@ -384,7 +384,7 @@ } if (options.IsAllowNulls) { - IEntityPersister persister = @event.Session.Factory.GetEntityPersister(@event.EntityClassName); + IEntityPersister persister = GetEntityPersister(@event.Session.Factory, @event.EntityClassName); if (!persister.IsInstance(old, @event.Session.EntityMode)) { return InconsistentRTNClassMarker; @@ -493,5 +493,32 @@ } return result; } + + protected virtual IEntityPersister GetEntityPersister(ISessionFactoryImplementor factory, string entityName) + { + // Check for an exact match. + IEntityPersister persister = factory.TryGetEntityPersister(entityName); + if (persister != null) + { + return persister; + } + + // Couldn't find persister through exact name, try finding a single implementing class. + string[] implementors = factory.GetImplementors(entityName); + if (implementors.Length > 1) + { + var messageBuilder = new StringBuilder(512); + messageBuilder.AppendLine(string.Format("Ambiguous persister for {0} implemented by more than one hierarchy: ", + entityName)); + Array.ForEach(implementors, s=> messageBuilder.AppendLine(s)); + + throw new HibernateException(messageBuilder.ToString()); + } + if (implementors.Length == 0) + { + return null; + } + return factory.GetEntityPersister(implementors[0]); + } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-09-26 14:26:22 UTC (rev 5223) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-09-26 16:54:16 UTC (rev 5224) @@ -517,6 +517,8 @@ <Compile Include="NHSpecificTest\NH2331\Person.cs" /> <Compile Include="NHSpecificTest\NH2344\Fixture.cs" /> <Compile Include="NHSpecificTest\NH2344\Model.cs" /> + <Compile Include="PolymorphicGetAndLoad\Domain.cs" /> + <Compile Include="PolymorphicGetAndLoad\PolymorphicGetAndLoadTest.cs" /> <Compile Include="TypesTest\CharClass.cs" /> <Compile Include="TypesTest\CharClassFixture.cs" /> <Compile Include="TypesTest\DateTimeClass.cs" /> @@ -2312,6 +2314,7 @@ <EmbeddedResource Include="CollectionTest\NullableValueTypeElementMapFixture.hbm.xml" /> <EmbeddedResource Include="DriverTest\EntityForMs2008.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="PolymorphicGetAndLoad\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2331\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2324\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2344\Mappings.hbm.xml" /> @@ -2655,7 +2658,6 @@ <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> </ItemGroup> <ItemGroup> - <Folder Include="NHSpecificTest\NH2202" /> <Folder Include="Properties\" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> Added: trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Domain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Domain.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Domain.cs 2010-09-26 16:54:16 UTC (rev 5224) @@ -0,0 +1,41 @@ +namespace NHibernate.Test.PolymorphicGetAndLoad +{ + public class A: INamed + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public interface IOccuped + { + string Occupation { get; set; } + } + + public class B: A, IOccuped + { + public virtual string Occupation { get; set; } + } + + public interface INamed + { + string Name { get; set; } + } + + public class GraphA : IMultiGraphNamed + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class GraphB : IMultiGraphNamed + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public interface IMultiGraphNamed + { + string Name { get; set; } + } + +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/Mappings.hbm.xml 2010-09-26 16:54:16 UTC (rev 5224) @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping + xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.PolymorphicGetAndLoad"> + + <class name="A"> + <id name="Id"> + <generator class="hilo" /> + </id> + <property name="Name"/> + <joined-subclass name="B"> + <key column="AId"/> + <property name="Occupation"/> + </joined-subclass> + </class> + + <class name="GraphA"> + <id name="Id"> + <generator class="hilo" /> + </id> + <property name="Name"/> + </class> + + <class name="GraphB"> + <id name="Id"> + <generator class="hilo" /> + </id> + <property name="Name"/> + </class> + +</hibernate-mapping> \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/PolymorphicGetAndLoadTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/PolymorphicGetAndLoadTest.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/PolymorphicGetAndLoad/PolymorphicGetAndLoadTest.cs 2010-09-26 16:54:16 UTC (rev 5224) @@ -0,0 +1,260 @@ +using System; +using System.Collections; +using NHibernate.Engine; +using NHibernate.Proxy; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.PolymorphicGetAndLoad +{ + public class PolymorphicGetAndLoadTest: TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new[] { "PolymorphicGetAndLoad.Mappings.hbm.xml" }; } + } + + public class ScenarioWithA : IDisposable + { + private readonly ISessionFactory factory; + private readonly A a; + + public ScenarioWithA(ISessionFactory factory) + { + this.factory = factory; + a = new A { Name = "Patrick" }; + using (var s = factory.OpenSession()) + { + s.Save(a); + s.Flush(); + } + } + + public A A + { + get { return a; } + } + + public void Dispose() + { + using (var s = factory.OpenSession()) + { + s.Delete(a); + s.Flush(); + } + } + } + + public class ScenarioWithB : IDisposable + { + private readonly ISessionFactory factory; + private readonly B b; + + public ScenarioWithB(ISessionFactory factory) + { + this.factory = factory; + b = new B { Name = "Patrick", Occupation = "hincha pelotas (en el buen sentido), but good candidate to be committer."}; + using (var s = factory.OpenSession()) + { + s.Save(b); + s.Flush(); + } + } + + public B B + { + get { return b; } + } + + public void Dispose() + { + using (var s = factory.OpenSession()) + { + s.Delete(b); + s.Flush(); + } + } + } + + [Test] + public void WhenSaveDeleteBaseClassCastedToInterfaceThenNotThrows() + { + INamed a = new A { Name = "Patrick" }; + Executing.This(() => + { + using (var s = OpenSession()) + { + s.Save(a); + s.Flush(); + } + }).Should().NotThrow(); + + Executing.This(() => + { + using (var s = OpenSession()) + { + s.Delete(a); + s.Flush(); + } + }).Should().NotThrow(); + + } + + [Test] + public void WhenLoadBaseClassUsingInterfaceThenNotThrows() + { + using (var scenario = new ScenarioWithA(Sfi)) + { + using (var s = OpenSession()) + { + s.Executing(session => session.Load<INamed>(scenario.A.Id)).NotThrows(); + } + } + } + + [Test] + public void WhenGetBaseClassUsingInterfaceThenNotThrows() + { + using (var scenario = new ScenarioWithA(Sfi)) + { + using (var s = OpenSession()) + { + s.Executing(session => session.Get<INamed>(scenario.A.Id)).NotThrows(); + } + } + } + + [Test] + public void WhenLoadInheritedClassUsingInterfaceThenNotThrows() + { + using (var scenario = new ScenarioWithB(Sfi)) + { + using (var s = OpenSession()) + { + Executing.This(()=> s.Load<INamed>(scenario.B.Id) ).Should().NotThrow(); + } + } + } + + [Test] + public void WhenLoadInheritedClassUsingInterfaceThenShouldAllowNarrowingProxy() + { + using (var scenario = new ScenarioWithB(Sfi)) + { + using (var s = OpenSession()) + { + INamed loadedEntity = null; + Executing.This(() => loadedEntity = s.Load<INamed>(scenario.B.Id)).Should().NotThrow(); + NHibernateProxyHelper.GetClassWithoutInitializingProxy(loadedEntity).Should().Be(typeof(A)); + + var narrowedProxy = s.Load<B>(scenario.B.Id); + + NHibernateProxyHelper.GetClassWithoutInitializingProxy(narrowedProxy).Should().Be(typeof(B)); + + var firstLoadedImpl = ((INHibernateProxy)loadedEntity).HibernateLazyInitializer.GetImplementation((ISessionImplementor)s); + var secondLoadedImpl = ((INHibernateProxy)narrowedProxy).HibernateLazyInitializer.GetImplementation((ISessionImplementor)s); + firstLoadedImpl.Should().Be.SameInstanceAs(secondLoadedImpl); + } + } + } + + [Test] + public void WhenLoadInterfaceThenShouldAllowNarrowingProxy() + { + using (var scenario = new ScenarioWithB(Sfi)) + { + using (var s = OpenSession()) + { + INamed loadedEntity = null; + Executing.This(() => loadedEntity = s.Load<INamed>(scenario.B.Id)).Should().NotThrow(); + NHibernateProxyHelper.GetClassWithoutInitializingProxy(loadedEntity).Should().Be(typeof(A)); + + var narrowedProxy = s.Load<IOccuped>(scenario.B.Id); + + NHibernateProxyHelper.GetClassWithoutInitializingProxy(narrowedProxy).Should().Be(typeof(B)); + + var firstLoadedImpl = ((INHibernateProxy)loadedEntity).HibernateLazyInitializer.GetImplementation((ISessionImplementor)s); + var secondLoadedImpl = ((INHibernateProxy)narrowedProxy).HibernateLazyInitializer.GetImplementation((ISessionImplementor)s); + firstLoadedImpl.Should().Be.SameInstanceAs(secondLoadedImpl); + } + } + } + + [Test] + public void WhenGetInheritedClassUsingInterfaceThenNotThrows() + { + using (var scenario = new ScenarioWithB(Sfi)) + { + using (var s = OpenSession()) + { + INamed loadedEntity = null; + Executing.This(() => loadedEntity = s.Get<INamed>(scenario.B.Id)).Should().NotThrow(); + loadedEntity.Should().Be.OfType<B>(); + } + } + } + + [Test] + public void WhenLoadClassUsingInterfaceOfMultippleHierarchyThenThrows() + { + using (var s = OpenSession()) + { + Executing.This(() => s.Load<IMultiGraphNamed>(1)) + .Should().Throw<HibernateException>() + .And.ValueOf.Message.Should() + .Contain("Ambiguous") + .And.Contain("GraphA") + .And.Contain("GraphB") + .And.Contain("IMultiGraphNamed"); + } + } + + [Test] + public void WhenGetClassUsingInterfaceOfMultippleHierarchyThenThrows() + { + using (var s = OpenSession()) + { + Executing.This(() => s.Get<IMultiGraphNamed>(1)) + .Should().Throw<HibernateException>() + .And.ValueOf.Message.Should() + .Contain("Ambiguous") + .And.Contain("GraphA") + .And.Contain("GraphB") + .And.Contain("IMultiGraphNamed"); + } + } + + [Test] + public void WhenGetBaseClassUsingInterfaceFromSessionCacheThenNotThrows() + { + using (var scenario = new ScenarioWithA(Sfi)) + { + using (var s = OpenSession()) + { + var id = scenario.A.Id; + s.Get<A>(id); + s.Executing(session => session.Get<INamed>(id)).NotThrows(); + } + } + } + + [Test] + public void WhenGetInheritedClassUsingInterfaceFromSessionCacheThenNotThrows() + { + using (var scenario = new ScenarioWithB(Sfi)) + { + using (var s = OpenSession()) + { + var id = scenario.B.Id; + s.Get<B>(id); + s.Executing(session => session.Get<INamed>(id)).NotThrows(); + } + } + } + } +} \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |