kubut
kubut

Reputation: 315

NHibernate: Invalid Cast (check your mapping for property type mismatches);

I have a class ProductCategoryModel:

public class ProductCategoryModel
{
    public virtual int id { get; set; }
    public virtual string name { get; set; }
    public virtual int parentId { get; set; }
    public virtual Iesi.Collections.Generic.ISet<ProductCategoryModel> subCategory { get; set; }
}

And here is my mapping xml:

    <?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Shop.Domain.Model.ProductCategory" assembly="Shop.Domain">
  <class name="ProductCategoryModel">
    <id name="id" column="id">
      <generator class="native" />
    </id>
    <property name="name" not-null="true" length="50" type="string" column="name"/>
    <many-to-one name="parentId" not-null="true" class="ProductCategoryModel" column="parentId"/>
    <set name="subCategory" inverse="true">
      <key column="parentId"/>
      <one-to-many class="ProductCategoryModel"/>
    </set>
  </class>
</hibernate-mapping>

My table on database contains:

id: 2, name: "...", parentId: 0
id: 3, name: "...", parentId: 2 
id: 4, name: "...", parentId: 2

Now I want to select my category with id 2:

session1.Get<ProductCategoryModel>(id);

but Nhibernate throw exception:

        NHibernate.PropertyAccessException was unhandled
  HResult=-2146232832
  Message=Invalid Cast (check your mapping for property type mismatches); setter of Shop.Domain.Model.ProductCategory.ProductCategoryModel
  Source=NHibernate
  StackTrace:
       w NHibernate.Tuple.Entity.PocoEntityTuplizer.SetPropertyValuesWithOptimizer(Object entity, Object[] values)
       w NHibernate.Tuple.Entity.PocoEntityTuplizer.SetPropertyValues(Object entity, Object[] values)
       w NHibernate.Persister.Entity.AbstractEntityPersister.SetPropertyValues(Object obj, Object[] values, EntityMode entityMode)
       w NHibernate.Engine.TwoPhaseLoad.InitializeEntity(Object entity, Boolean readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent)
       w NHibernate.Loader.Loader.InitializeEntitiesAndCollections(IList hydratedObjects, Object resultSetId, ISessionImplementor session, Boolean readOnly)
       w NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer)
       w NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer)
       w NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
       w NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister)
       w NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId)
       w NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session)
       w NHibernate.Persister.Entity.AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
       w NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
       w NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
       w NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
       w NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
       w NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType)
       w NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType)
       w NHibernate.Impl.SessionImpl.Get(String entityName, Object id)
       w NHibernate.Impl.SessionImpl.Get(Type entityClass, Object id)
       w NHibernate.Impl.SessionImpl.Get[T](Object id)
       w Shop.Infrastructure.Repositories.ProductCategoryIM.GetCategoryById(Int32 id) w f:\Uczelnia\!Semestr VI\Kurs aplikacji bazodanowych\KubutShop2\KubutShop\Shop.Infrastructure\Repositories\ProductCategoryIM.cs:wiersz 58
       w Shop.Application.Front.FrontService.GetProductCategoryById(Int32 id) w f:\Uczelnia\!Semestr VI\Kurs aplikacji bazodanowych\KubutShop2\KubutShop\Shop.Application\Front\Front.cs:wiersz 139
       w Presentation.ConsoleApp.Program.Main(String[] args) w f:\Uczelnia\!Semestr VI\Kurs aplikacji bazodanowych\KubutShop2\KubutShop\Presentation.ConsoleApp\Program.cs:wiersz 40
       w System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       w System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       w Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       w System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       w System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       w System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       w System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       w System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.InvalidCastException
       HResult=-2147467262
       Message=Nie można rzutować obiektu typu 'NHibernate.Collection.Generic.PersistentGenericSet`1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]' na typ 'Iesi.Collections.Generic.ISet`1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]'.
       Source=Shop.Domain
       StackTrace:
            w (Object , Object[] , SetterCallback )
            w NHibernate.Bytecode.Lightweight.AccessOptimizer.SetPropertyValues(Object target, Object[] values)
            w NHibernate.Tuple.Entity.PocoEntityTuplizer.SetPropertyValuesWithOptimizer(Object entity, Object[] values)
       InnerException: 

Message=Nie można rzutować obiektu typu 'NHibernate.Collection.Generic.PersistentGenericSet1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]' na typ Iesi.Collections.Generic.ISet1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]'.

means something like this:

Message=Cannot cast 'NHibernate.Collection.Generic.PersistentGenericSet1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]' to type Iesi.Collections.Generic.ISet1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]'

What I'm doing wrong? I read a lot of similar topics, but I still have no idea where is a mistake. P.S. Sorry for my terrible English ;)

Upvotes: 2

Views: 6417

Answers (1)

Radim K&#246;hler
Radim K&#246;hler

Reputation: 123861

With a latest 4.0+ NHibernate version we should keep in mind really crucial change, described here, in this Q & A

Let me cite a bit (from release notes):

** Known BREAKING CHANGES from NH3.3.3.GA to 4.0.0.GA

NHibernate now targets .Net 4.0. Many uses of set types from Iesi.Collections have now been changed to use corresponding types from the BCL. The API for these types are slightly different.

So - now we are about to use System not iesi stuff, e.g.:

System.Collections.Generic.ISet<T>

The second thing, very important, is that we need to create bi-directional mapping, one-to-many and many-to-one. That means we cannot

// not iesi
// we need System
using System.Collections.Generic;
using System.Collections.ObjectModel;

...

public class ProductCategoryModel
{
    ...
    // could be used just as navigation property
    public virtual int parentId { get; set; }
    // This is must with inverse="true"
    public virtual ProductCategoryModel Parent { get; set; }
    // the System.Collections.Generic
    public virtual ISet<ProductCategoryModel> SubCategories { get; set; }
    ...

And mapping:

...
// readonly
<property  name="parentId" not-null="true" column="parentId" type="string"
                                      insert="false" update="false" />
// inverse end
<many-to-one name="Parent" not-null="true" class="ProductCategoryModel" column="parentId"/>

<set name="SubCategories" inverse="true" batch-size="25">
  <key column="parentId"/>
  <one-to-many class="ProductCategoryModel"/>
</set>
...

As we can see, we can have mapping for both many-to-one (reference) and for property (valueType or string). One of them must be readonly (insert="false" update="false")

NOTE: Do not forget, that because we use inverse, we have to set both sides of relation in C#...

Upvotes: 1

Related Questions