These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Custom collection implementations with NHibernate
PostPosted: Wed Apr 02, 2008 9:53 pm 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
Hibernate version: 1.2.1

I am a little confused with this paragraph in documentation

When you make the instance persistent- by calling Save(), for example - NHibernate will actually replace the HashedSet with an instance of
NHibernate's own implementation of ISet. Watch out for errors like this:
Code:
Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
ISet kittens = new HashedSet();
kittens.Add(kitten);
cat.Kittens = kittens;
session.Save(cat);
kittens = cat.Kittens; //Okay, kittens collection is an ISet
HashedSet hs = (HashedSet) cat.Kittens; //Error!


I have a custom implementation of collection that implements IList<T>, IEnumerable<T> and ICollection<T> plus some additional methods. On my custom types I want collections to be exposed as EntityBag<T> rather then ISet interface. Is it possible?
For example I want to be able to do something like this inv.LineItems.MyCustomMethodOnTheBag(), where LineItems is expossed as EntityBag<LineItem>.
Can somebody clarify this.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 5:24 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Hibernate uses its own list implementations (for handling lazy loading and more), therefore you have to use the interfaces. And hibernate replaces the lists, so you can't do what you want in that way. But there are a few solutions for that.

1) NHibernate.
UserType.IUserCollectionType
You can implement this interface on your lists, too, then hibernate will use you list instead of its own.

2) You can wrap the hibernate lists with you list
Code:
    <component name="..." class="EntityBag`1[[T]]">
      <bag name="Items" table="..." ">
             ....
      </bag>
    </component>

Items points to the internal hibernate list. You can pass through the ICollection, IList, ... interface to the internal list and add your functionality to the wrapper.

3) You can return "copies" of your lists

Code:
private IList<T> _list
public EntityBag<T> List
{
     get { return new EntityBag<T>(_list); }
     set { "copy items into _list"; }
}


This can surely be implemented smarter, but I just wanted to show the idea.

Hope that helps,
Wolfgang

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:31 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
wolli, thank you very much. You've been very helpful past several day in answering my NHibernate beginner questions.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:34 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
in short term, solution 2 seems to be the easiest to implement. Are there any hidden problems with it?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:40 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Not really, we use it that way and it's working fine. You simply have to put some work into it if you want functionality from List<T> (if your custom list is derived from that). If you only need the interfaces, it's straight forward.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:40 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
Ok, first sentence in documentation seems like problematic for solution 2.

Quote:
A component is a contained object that is persisted as a value type, not an entity


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:52 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
I think what's meant there is a component with properties defined in it. These will be mapped to the same table like the class where it is defined in. But the construct I use only contains the bag with the one-to-many association and I never discovered any differences to "normally" mapped collection.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 9:58 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
So, how do I rate the posts. I don't see the option anywhere.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 10:08 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
There should be a line at the end of my posts:

Quote:
Please rate this answer to give credits to the poster! Did it solve the problem? Yes / No


With Yes/No as links.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 10:53 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
I get this errror

InnerException: NHibernate.MappingException
Message="could not find class: Intelliun.Collections.EntityBag`1[T], Intelliun.Common"
Source="NHibernate"

mapped like this

<component name="lineItems" class="Intelliun.Collections.EntityBag`1[T], Intelliun.Common">
<bag name="lineItems" inverse="true" lazy="true" cascade="all" access="field.camelcase-underscore">
<key column="INVOICE_VEOID"/>
<one-to-many class="LineItem"/>
</bag>
</component>

Also, can it be lazyloaded and can association be inverse?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 11:03 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
You can't use T as generic parameter there. You have to use the correct generic parameter:

Code:
< ... class="Intelliun.Collections.EntityBag`1[[Invoice]], Intelliun.Common">


And I'm never sure about if you need one [ or [[. If I remember it correctly you nee [[ if you also specify the assembly for the generic type.

For the rest, you can use the collection mapping like a normal collection mapping, e.g. lazy loading, inverse, ... whatever you want.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 11:09 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
I did use specific type instead of T but it did not work, then I said who knows maybe I need a T. Problem is that they come from two assebmlies. But I did not know about [[ needing two. So let me try to fully qualify both types.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 11:12 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
When you have different assemblies, you need something like that:

< ... class="Intelliun.Collections.EntityBag`1[[Invoice, Intelliun.xxx]], Intelliun.Common">

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 11:16 am 
Regular
Regular

Joined: Tue Oct 16, 2007 9:45 am
Posts: 93
Ok, I am past that problem, i mapped it like this
Code:
<component name="lineItems2" class="Intelliun.Collections.EntityBag`1[[Intelliun.Core.Entities.billing.LineItem,Intelliun.Core]], Intelliun.Common">
      <bag name="lineItems" inverse="true" lazy="true" cascade="all" >
        <key column="INVOICE_VEOID"/>
        <one-to-many class="LineItem"/>
      </bag>


but now I have this message

InnerException: NHibernate.PropertyNotFoundException
Message="Could not find a getter for property 'lineItems' in class 'Intelliun.Collections.EntityBag`1[Intelliun.Core.Entities.billing.LineItem]'"
Source="NHibernate"
StackTrace:
at NHibernate.Property.BasicPropertyAccessor.GetGetter(Type type, String propertyName)
at NHibernate.Util.ReflectHelper.GetGetter(Type theClass, String propertyName, String propertyAccessorName)
at NHibernate.Util.ReflectHelper.ReflectedPropertyClass(Type theClass, String name, String access)
at NHibernate.Cfg.HbmBinder.GetPropertyType(XmlNode definingNode, Mappings mappings, Type containingType, String propertyName)
at NHibernate.Cfg.HbmBinder.BindCollection(XmlNode node, Collection model, String className, String path, Type containingType, Mappings mappings)
at NHibernate.Cfg.HbmBinder.CollectionType.CollectionTypeBag.Create(XmlNode node, String prefix, String path, PersistentClass owner, Type containingType, Mappings mappings)
at NHibernate.Cfg.HbmBinder.BindComponent(XmlNode node, Component model, Type reflectedClass, String className, String path, Boolean isNullable, Mappings mappings)
at NHibernate.Cfg.HbmBinder.PropertiesFromXML(XmlNode node, PersistentClass model, Mappings mappings)
at NHibernate.Cfg.HbmBinder.BindRootClass(XmlNode node, RootClass model, Mappings mappings)
at NHibernate.Cfg.HbmBinder.BindRoot(XmlDocument doc, Mappings mappings)
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc)
InnerException:


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 11:18 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Do you have one ? In your fist mapping you used access="field.camelcase-underscore

_________________
--Wolfgang


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.