Reputation: 315
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.PersistentGenericSet
1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]' na typ Iesi.Collections.Generic.ISet
1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]'.
means something like this:
Message=Cannot cast 'NHibernate.Collection.Generic.PersistentGenericSet
1[Shop.Domain.Model.ProductCategory.ProductCategoryModel]' to type Iesi.Collections.Generic.ISet
1[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
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