I'm trying to create a IUserCollectionType to map a custom generic dictionary without much success:
The custom interface:
Code:
/// <summary>
/// Simple extension of an <see cref="IDictionary{TKey,TValue}"/>. This is pretty much as per
/// http://www.martinfowler.com/eaaDev/TemporalProperty.html, with the only deviation being that I am extending an
/// <see cref="IDictionary{TKey,TValue}"/>
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
public interface IMilestoneCollection<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey>
{
/// <summary>
/// Finds the item that is relevant for the <paramref name="value"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
TValue FindItemFor(TKey value);
}
In my concrete implementation of this interface I am basically decorating (i.e wrapping) a Dictionary, to allow me to cache the milestones in reverse order whenever it is updated.
I've created an implementation of IUserCollectionType & PersistentGenericMap to allow me to map this:
Code:
public class MilestoneCollectionType<TKey, TValue> : IUserCollectionType
where TKey : IComparable<TKey>
{
#region IUserCollectionType Members
public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
{
return new PersistentMilestoneCollection<TKey, TValue>(session);
}
public IPersistentCollection Wrap(ISessionImplementor session, object collection)
{
return new PersistentMilestoneCollection<TKey, TValue>(session, (IMilestoneCollection<TKey, TValue>) collection);
}
public IEnumerable GetElements(object collection)
{
return (IEnumerable) collection;
}
public bool Contains(object collection, object entity)
{
return ((IMilestoneCollection<TKey, TValue>)collection).Contains((KeyValuePair<TKey, TValue>)entity);
}
public object IndexOf(object collection, object entity)
{
throw new NotImplementedException();
}
public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
{
throw new NotImplementedException();
}
public object Instantiate()
{
return new MilestoneCollection<TKey, TValue>();
}
#endregion
}
public class HistoricAddressCollectionType : MilestoneCollectionType<DateTime, Address>{}
public class PersistentMilestoneCollection<TKey, TValue> : PersistentGenericMap<TKey, TValue>, IMilestoneCollection<TKey, TValue>
where TKey : IComparable<TKey>
{
public PersistentMilestoneCollection(ISessionImplementor session) : base(session){}
public PersistentMilestoneCollection(ISessionImplementor session, IMilestoneCollection<TKey, TValue> map) : base(session, map){}
#region IMilestoneCollection<TValue> Members
public TValue FindItemFor(TKey value)
{
Read();
return ((IMilestoneCollection<TKey, TValue>) map).FindItemFor(value);
}
#endregion
}
and my mapping file is :
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="none"
xmlns="urn:nhibernate-mapping-2.2"
assembly="UserTypeExample.Domain"
namespace="UserTypeExample.Domain">
<class name="Person" table="People" lazy="false">
<id name="Id" column="PersonId">
<generator class="identity" />
</id>
<version name="_version" column="Version" access="field" />
<property name="Name" column="Name" />
<map name="_addresses"
access="field"
generic="true"
table="HistoricAddresses"
collection-type="UserTypeExample.Persistence.HistoricAddressCollectionType, UserTypeExample.Persistence"
cascade="all-delete-orphan">
<key column="PersonId" />
<index column="StartDate" type="System.DateTime"/>
<one-to-many class="Address"/>
</map>
</class>
</hibernate-mapping>
However, when I call ISession.SaveOrUpdate I get the following exception:
Quote:
NHibernate.MappingException was unhandled
Message="Unknown entity class: System.Collections.Generic.KeyValuePair`2[[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[UserTypeExample.Domain.Address, UserTypeExample.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
Source="NHibernate"
StackTrace:
at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(Type theClass)
at NHibernate.Impl.SessionImpl.GetClassPersister(Type theClass)
at NHibernate.Impl.SessionImpl.GetEntityPersister(Object obj)
at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
at NHibernate.Engine.Cascades.CascadingAction.ActionSaveUpdateClass.Cascade(ISessionImplementor session, Object child, Object anything)
at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, Object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, Object anything)
at NHibernate.Engine.Cascades.CascadeCollection(CascadingAction action, CascadeStyle style, CollectionType collectionType, IType elemType, Object child, CascadePoint cascadeVia, ISessionImplementor session, Object anything)
at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, Object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, Object anything)
at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, IEntityPersister persister, Object parent, CascadingAction action, CascadePoint cascadeTo, Object anything)
at NHibernate.Impl.SessionImpl.DoSave(Object theObj, EntityKey key, IEntityPersister persister, Boolean replicate, Boolean useIdentityColumn, CascadingAction cascadeAction, Object anything)
at NHibernate.Impl.SessionImpl.DoSave(Object obj, Object id, IEntityPersister persister, Boolean useIdentityColumn, CascadingAction cascadeAction, Object anything)
at NHibernate.Impl.SessionImpl.SaveWithGeneratedIdentifier(Object obj, CascadingAction action, Object anything)
at NHibernate.Impl.SessionImpl.Save(Object obj)
at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
at SevenIM.Persistence.NHibernateHelper`2.SaveOrUpdate(TPersistableObject toSaveOrUpdate)
at SevenIM.Persistence.NHibernateRepository`2.SaveOrUpdate(TPersistableObject toSaveOrUpdate)
at UserTypeExample.ConsoleApp.Runner.CreateBaseDate() in C:\vs 2005\main\Test\UserTypeExample\UserTypeExample.ConsoleApp\Runner.cs:line 43
at UserTypeExample.ConsoleApp.Runner.Main(String[] args) in C:\vs 2005\main\Test\UserTypeExample\UserTypeExample.ConsoleApp\Runner.cs:line 22
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
any ideas?... should I be using IUserCollectionType for a custom Dictionary.
N.B. I was getting an exception when the SessionFactory was being built, when I had collection-type="MilestoneCollectionType" which went away when I changed to collection-type="HistoricAddressCollectionType"