|
From: <fab...@us...> - 2011-03-28 16:03:13
|
Revision: 5565
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5565&view=rev
Author: fabiomaulo
Date: 2011-03-28 16:03:06 +0000 (Mon, 28 Mar 2011)
Log Message:
-----------
Fix NH-2489
Modified Paths:
--------------
trunk/nhibernate/releasenotes.txt
trunk/nhibernate/src/NHibernate/Collection/AbstractPersistentCollection.cs
trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericList.cs
trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericMap.cs
trunk/nhibernate/src/NHibernate/Collection/PersistentList.cs
trunk/nhibernate/src/NHibernate/Collection/PersistentMap.cs
trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
trunk/nhibernate/src/NHibernate/Persister/Collection/ICollectionPersister.cs
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/SetFixture.cs
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Fixture.cs
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Mappings.hbm.xml
trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Model.cs
Modified: trunk/nhibernate/releasenotes.txt
===================================================================
--- trunk/nhibernate/releasenotes.txt 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/releasenotes.txt 2011-03-28 16:03:06 UTC (rev 5565)
@@ -5,6 +5,7 @@
##### Possible Breaking Changes #####
* [NH-2550] - Allow public access to FieldInterceptor Session (IFieldInterceptor changed)
* [NH-2593] - Form Microsoft SQL Server the default batch-size (adonet.batch_size) is set to 20 where not explicit defined in the session-factory configuration
+ * - ICollectionPersister added property to fix [NH-2489]
Build 3.1.0.GA (rev5425)
=============================
Modified: trunk/nhibernate/src/NHibernate/Collection/AbstractPersistentCollection.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Collection/AbstractPersistentCollection.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Collection/AbstractPersistentCollection.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -19,6 +19,7 @@
public abstract class AbstractPersistentCollection : IPersistentCollection
{
protected internal static readonly object Unknown = new object(); //place holder
+ protected internal static readonly object NotFound = new object(); //place holder
protected interface IDelayedOperation
{
@@ -345,7 +346,8 @@
{
session.Flush();
}
- return persister.GetElementByIndex(entry.LoadedKey, index, session, owner);
+ var elementByIndex = persister.GetElementByIndex(entry.LoadedKey, index, session, owner);
+ return persister.NotFoundObject == elementByIndex ? NotFound : elementByIndex;
}
}
Read();
Modified: trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericList.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericList.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericList.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -88,10 +88,16 @@
{
return glist[index];
}
- else
+ if (result == NotFound)
{
- return (T) result;
+ // check if the index is valid
+ if (index >= Count)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ return default(T);
}
+ return (T) result;
}
set
{
@@ -107,7 +113,7 @@
}
else
{
- QueueOperation(new SetDelayedOperation(this, index, value, old));
+ QueueOperation(new SetDelayedOperation(this, index, value, old == NotFound ? null : old));
}
}
}
Modified: trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericMap.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericMap.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Collection/Generic/PersistentGenericMap.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -125,7 +125,7 @@
object old = ReadElementByIndex(key);
if (old != Unknown)
{
- QueueOperation(new PutDelayedOperation(this, key, value, old));
+ QueueOperation(new PutDelayedOperation(this, key, value, old == NotFound ? null : old));
return;
}
}
@@ -139,7 +139,7 @@
if (PutQueueEnabled)
{
object old = ReadElementByIndex(key);
- QueueOperation(new RemoveDelayedOperation(this, key, old));
+ QueueOperation(new RemoveDelayedOperation(this, key, old == NotFound ? null : old));
return true;
}
else
@@ -161,11 +161,13 @@
{
return gmap.TryGetValue(key, out value);
}
- else
+ if(result == NotFound)
{
- value = (TValue)result;
- return true;
+ value = default(TValue);
+ return false;
}
+ value = (TValue)result;
+ return true;
}
TValue IDictionary<TKey, TValue>.this[TKey key]
@@ -173,7 +175,15 @@
get
{
object result = ReadElementByIndex(key);
- return result == Unknown ? gmap[key] : (TValue)result;
+ if (result == Unknown)
+ {
+ return gmap[key];
+ }
+ if (result == NotFound)
+ {
+ throw new KeyNotFoundException();
+ }
+ return (TValue) result;
}
set
{
@@ -183,7 +193,7 @@
object old = ReadElementByIndex(key);
if (old != Unknown)
{
- QueueOperation(new PutDelayedOperation(this, key, value, old));
+ QueueOperation(new PutDelayedOperation(this, key, value, old == NotFound ? null : old));
return;
}
}
Modified: trunk/nhibernate/src/NHibernate/Collection/PersistentList.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Collection/PersistentList.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Collection/PersistentList.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -339,7 +339,7 @@
}
else
{
- QueueOperation(new RemoveDelayedOperation(this, index, old));
+ QueueOperation(new RemoveDelayedOperation(this, index, old == NotFound ? null : old));
}
}
@@ -352,7 +352,20 @@
throw new IndexOutOfRangeException("negative index");
}
object result = ReadElementByIndex(index);
- return result == Unknown ? list[index] : result;
+ if (result == Unknown)
+ {
+ return list[index];
+ }
+ if(NotFound == result)
+ {
+ // check if the index is valid
+ if(index >= Count)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ return null;
+ }
+ return result;
}
set
{
@@ -360,7 +373,19 @@
{
throw new IndexOutOfRangeException("negative index");
}
- object old = PutQueueEnabled ? ReadElementByIndex(index) : Unknown;
+ object old;
+ if (PutQueueEnabled)
+ {
+ old = ReadElementByIndex(index);
+ if(old == NotFound)
+ {
+ old = null;
+ }
+ }
+ else
+ {
+ old = Unknown;
+ }
if (old == Unknown)
{
Write();
Modified: trunk/nhibernate/src/NHibernate/Collection/PersistentMap.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Collection/PersistentMap.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Collection/PersistentMap.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -242,7 +242,7 @@
object old = ReadElementByIndex(key);
if (old != Unknown)
{
- QueueOperation(new PutDelayedOperation(this, key, value, old));
+ QueueOperation(new PutDelayedOperation(this, key, value, old == NotFound ? null : old));
return;
}
}
@@ -280,7 +280,10 @@
if (PutQueueEnabled)
{
object old = ReadElementByIndex(key);
- QueueOperation(new RemoveDelayedOperation(this, key, old));
+ if (old != NotFound)
+ {
+ QueueOperation(new RemoveDelayedOperation(this, key, old));
+ }
return;
}
else
@@ -302,7 +305,7 @@
get
{
object result = ReadElementByIndex(key);
- return result == Unknown ? map[key] : result;
+ return result == Unknown ? map[key] : (result == NotFound ? null : result);
}
set
{
@@ -310,7 +313,7 @@
if (PutQueueEnabled)
{
object old = ReadElementByIndex(key);
- if (old != Unknown)
+ if (old != Unknown && old != NotFound)
{
QueueOperation(new PutDelayedOperation(this, key, value, old));
return;
Modified: trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -34,6 +34,7 @@
public abstract class AbstractCollectionPersister : ICollectionMetadata, ISqlLoadableCollection,
IPostInsertIdentityPersister
{
+ protected static readonly object NotFoundPlaceHolder = new object();
private readonly string role;
#region SQL statements
@@ -1617,7 +1618,7 @@
}
else
{
- return null;
+ return NotFoundObject;
}
}
finally
@@ -1638,6 +1639,11 @@
}
}
+ public object NotFoundObject
+ {
+ get { return NotFoundPlaceHolder; }
+ }
+
public abstract bool ConsumesEntityAlias();
public abstract SqlString FromJoinFragment(string alias, bool innerJoin, bool includeSubclasses);
Modified: trunk/nhibernate/src/NHibernate/Persister/Collection/ICollectionPersister.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Persister/Collection/ICollectionPersister.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate/Persister/Collection/ICollectionPersister.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -273,6 +273,20 @@
int GetSize(object key, ISessionImplementor session);
bool IndexExists(object key, object index, ISessionImplementor session);
bool ElementExists(object key, object element, ISessionImplementor session);
+
+ /// <summary>
+ /// Try to find an element by a given index.
+ /// </summary>
+ /// <param name="key">The key of the collection (collection-owner identifier)</param>
+ /// <param name="index">The given index.</param>
+ /// <param name="session">The active <see cref="ISession"/>.</param>
+ /// <param name="owner">The owner of the collection.</param>
+ /// <returns>The value of the element where available; otherwise <see cref="NotFoundObject"/>.</returns>
object GetElementByIndex(object key, object index, ISessionImplementor session, object owner);
+
+ /// <summary>
+ /// A place-holder to inform that the data-reader was empty.
+ /// </summary>
+ object NotFoundObject { get; }
}
}
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Fixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Fixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Fixture.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using SharpTestsEx;
+
+namespace NHibernate.Test.NHSpecificTest.NH2489
+{
+ public class Fixture : BugTestCase
+ {
+ #region Scenarios
+
+ private class ListScenario : IDisposable
+ {
+ private readonly ISessionFactory factory;
+
+ public ListScenario(ISessionFactory factory)
+ {
+ this.factory = factory;
+ using (ISession s = factory.OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ var entity = new Base();
+ var child = new Child();
+ // null members are partially working for lists, can't have one at the end
+ // and can't use the Count property.
+ entity.Children = new List<Child> {null, child};
+ s.Save(entity);
+ t.Commit();
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ using (ISession s = factory.OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Delete("from Base");
+ s.Delete("from Child");
+ t.Commit();
+ }
+ }
+ }
+ }
+
+ private class MapScenario : IDisposable
+ {
+ private readonly ISessionFactory factory;
+
+ public MapScenario(ISessionFactory factory)
+ {
+ this.factory = factory;
+ using (ISession s = factory.OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ var entity = new Base();
+ entity.NamedChildren = new Dictionary<string, Child>
+ {
+ {"Child1", new Child()},
+ {"NullChild", null},
+ };
+ s.Save(entity);
+ t.Commit();
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ using (ISession s = factory.OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ s.Delete("from Base");
+ s.Delete("from Child");
+ t.Commit();
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ [Test]
+ public void List_InvalidIndex()
+ {
+ using (new ListScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ // accessing an invalid index should throw an exception
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.Children.Count.Should().Be.EqualTo(2);
+ NHibernateUtil.IsInitialized(entity.Children).Should().Be.False();
+ Executing.This(() => { Child ignored = entity.Children[2]; }).Should().Throw<ArgumentOutOfRangeException>();
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void List_NullChild()
+ {
+ using (new ListScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ // the list should only contain an item at index 0
+ // accessing an invalid index should throw an exception
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.Children.Count.Should().Not.Be.EqualTo(0);
+ //entity.Children.Count.Should().Be.EqualTo(2);
+ NHibernateUtil.IsInitialized(entity.Children).Should().Be.False();
+ var sigil = new Child();
+ Child child = sigil;
+ Executing.This(() => { child = entity.Children[0]; }).Should().NotThrow();
+ child.Should().Not.Be.EqualTo(sigil);
+ child.Should().Be.Null();
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void Map_Item()
+ {
+ using (new MapScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ // accessing an invalid key should fail or throw an exception, depending on method
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.NamedChildren.Count.Should().Be.EqualTo(2);
+ NHibernateUtil.IsInitialized(entity.NamedChildren).Should().Be.False();
+ Executing.This(() => { Child ignored = entity.NamedChildren["InvalidKey"]; }).Should().Throw<KeyNotFoundException>();
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void Map_TryGetValue_Invalid()
+ {
+ using (new MapScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ // accessing an invalid key should fail or throw an exception, depending on method
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.NamedChildren.Count.Should().Be.EqualTo(2);
+ NHibernateUtil.IsInitialized(entity.NamedChildren).Should().Be.False();
+ Child child;
+ entity.NamedChildren.TryGetValue("InvalidKey", out child).Should().Be.False();
+ child.Should().Be.Null();
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void Map_NullChild()
+ {
+ using (new MapScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.NamedChildren.Count.Should().Not.Be.EqualTo(0);
+ //entity.NamedChildren.Count.Should().Be.EqualTo(2);
+ NHibernateUtil.IsInitialized(entity.NamedChildren).Should().Be.False();
+ // null valued child shouldn't cause errors
+ var sigil = new Child();
+ Child child = sigil;
+ Assert.DoesNotThrow(() => { child = entity.NamedChildren["NullChild"]; });
+ child.Should().Not.Be.EqualTo(sigil);
+ child.Should().Be.Null();
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void Map_NullChild_TryGetValue()
+ {
+ using (new MapScenario(Sfi))
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction t = s.BeginTransaction())
+ {
+ var entity = s.CreateQuery("from Base").UniqueResult<Base>();
+ // null collection members don't seem to work, at least for lazy="extra" collections
+ entity.NamedChildren.Count.Should().Not.Be.EqualTo(0);
+ //entity.NamedChildren.Count.Should().Be.EqualTo(2);
+ // null valued child shouldn't cause errors
+ NHibernateUtil.IsInitialized(entity.NamedChildren).Should().Be.False();
+ Child child;
+ entity.NamedChildren.TryGetValue("NullChild", out child)
+ .Should().Be.True();
+ child.Should().Be.Null();
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Mappings.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Mappings.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Mappings.hbm.xml 2011-03-28 16:03:06 UTC (rev 5565)
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ namespace="NHibernate.Test.NHSpecificTest.NH2489"
+ assembly="NHibernate.Test"
+>
+ <class name="Base" >
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ <list name="Children" lazy="extra" cascade="all">
+ <key column="listparentid"/>
+ <!-- sqlite doesn't like a column named index -->
+ <index column="childindex"/>
+ <many-to-many class="Child"/>
+ </list>
+ <map name="NamedChildren" lazy="extra" cascade="all" >
+ <key column="mapparentid" />
+ <index column="name" type="string" />
+ <many-to-many class="Child">
+ <column name="Child" not-null="false" />
+ </many-to-many>
+ </map>
+ </class>
+
+ <class name="Child">
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ </class>
+
+</hibernate-mapping>
Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Model.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Model.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2489/Model.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.NH2489
+{
+ public class Base
+ {
+ public virtual int Id
+ {
+ get;
+ set;
+ }
+
+ public virtual IList<Child> Children
+ {
+ get;
+ set;
+ }
+
+ public virtual IDictionary<string, Child> NamedChildren
+ {
+ get;
+ set;
+ }
+ }
+
+ public class Child
+ {
+ public virtual int Id
+ {
+ get;
+ set;
+ }
+ }
+}
Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/SetFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/SetFixture.cs 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/SetFixture.cs 2011-03-28 16:03:06 UTC (rev 5565)
@@ -343,6 +343,11 @@
throw new NotImplementedException();
}
+ public object NotFoundObject
+ {
+ get { throw new NotImplementedException(); }
+ }
+
public ISessionFactoryImplementor Factory
{
get { return null; }
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-03-28 15:15:24 UTC (rev 5564)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-03-28 16:03:06 UTC (rev 5565)
@@ -656,6 +656,8 @@
<Compile Include="NHSpecificTest\NH2484\Model.cs" />
<Compile Include="NHSpecificTest\NH2488\Fixture.cs" />
<Compile Include="NHSpecificTest\NH2488\Model.cs" />
+ <Compile Include="NHSpecificTest\NH2489\Fixture.cs" />
+ <Compile Include="NHSpecificTest\NH2489\Model.cs" />
<Compile Include="NHSpecificTest\NH2490\Fixture.cs" />
<Compile Include="NHSpecificTest\NH2490\Model.cs" />
<Compile Include="NHSpecificTest\NH2491\Fixture.cs" />
@@ -2498,6 +2500,7 @@
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
</ItemGroup>
<ItemGroup>
+ <EmbeddedResource Include="NHSpecificTest\NH2489\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2603\Mappings.hbm.xml" />
<EmbeddedResource Include="Subselect\Beings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2488\Mappings.hbm.xml" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|