Hibernate version:
2.0.1GA
Error:
Unable to cast object of type 'NHibernate.Collection.PersistentBag' to type 'Intellident.Vision.Domain.SupplyChain.Interfaces.IContents
Issue
I'm trying to implement a pure Persistence Ignorance pattern. At the moment I have:
UI
|
V
Domain Interfaces
^
|
Domain
^
|
DAL (NHibernate) - this also depends on Domain Interfaces but it doesn't show well here
and I'm using Microsoft Unity to tie it all together. I do not want any reference to the NHibernate DLL in any layer except the DAL. My mappings are also held in the DAL.
I have created a business collection that is typed and wraps an internal List<T> collection. This collection implements the IList<T> and IList
interfaces as well as some custom mehods (e.g. Sort) that are not in the interfaces themselves.
snip==>
public abstract class DomainCollection<T> : IDomainCollection<T>
{
private List<T> _list;
protected DomainCollection()
{
_list = new List<T>();
}
public void Add(T item)
{
_list.Add(item);
}
...
...
}
public interface IDomainCollection<T> : ICollection<T>, IList<T>, IList
{
...
...
}
<==snip
I've played about with this a bit so it probably isn't perfect inheritance now but you get the idea. Each business collection is of this type. I have an interface for each collection defined in my interface layer e.g.
public interface IContents: IDomainCollection<IContent>
{
}
My business class then has something like:
public interface IAsset
{
Guid Id { get; }
IContents Content{ get; }
void AddContent(IContent thing);
}
So far so good. I accept its a slight overkill on the IContents but it is purely business specific and allows extension to IContents later.
If I try the following NHibernate code in the DAL WITHOUT the IContents map
public IAssets ListAllThatAreEmpty()
{
Assets assets = new Assets();
Session.CreateCriteria(typeof(Asset))
.Add(Restrictions.Eq("Name","useme"))
.List(assets);
return assets;
}
then it works great. Assets implements IList so the collection is populated. The moment I add IContents as a property to IAsset and implement it in the concreate class such as this:
public virtual IContents Contents
{
get { return _contents; }
}
I get the error listed above.
I accept there may be an issue with my mapping file dealing with concrete classes as opposed to interfaces but I'd expect the previous NHibernate code to still work.
I really don't want to have my business classes have properties that return IList<T>. For starters, Generics screws me over as I have to return concrete classes not IList<interface types>, IList doesn't implement useful features like sort and lastly... it's just plain wrong. I have to change my domain layer for NHibernate.
When my custom collection class implements every"list" interface and property I can think of... I don't know why NHibernate can't cast to it... Have done something really stupid? - or, any advice to how to change my design keeping interface access to the domain layer and absolute domain persistence ignorance?
Mapping documents:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
namespace="Domain.Supply"
assembly="Domain.Supply"
default-access="field.camelcase-underscore">
<class name="Asset" table="Asset">
<id name="Id" column="Id" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<property name="Name" type="string" length="100" not-null="true" />
<bag name="Contents" table="Contents" lazy="true" inverse="true" cascade="all-delete-orphan" >
<key column="AssetId" />
<one-to-many class="Content" />
</bag>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
namespace="Domain.Supply"
assembly="Domain.Supply"
default-access="field.camelcase-underscore">
<class name="Content" table="Content">
<id name="Id" column="Id" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<property name="Description" type="string" length="255" not-null="true" />
</class>
</hibernate-mapping>
|