-->
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.  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Using a bag with set semantics
PostPosted: Sun May 28, 2006 3:41 pm 
Newbie

Joined: Sun May 28, 2006 2:42 pm
Posts: 14
"Hibernate in action" page 231 describes how to map a one-to-many association with a bag having set semantics. I have 3 classes: Facility, Contact and EU. A facility has 0 or more EU's and zero or more Contacts. Since my GUI is written in JSF,I would like to use java.util.List's as opposed to java.util.Set's. The problem is that when I try to fetch a Facility and associated Contacts and EU's with an outer join, I get duplicate Contacts:

Facility facility = (Facility)session.createCriteria(Facility.class)
.setFetchMode("contacts", FetchMode.JOIN)
.setFetchMode("eus", FetchMode.JOIN)
.add(Restrictions.idEq(pk))
.uniqueResult();

In other words, the bag appears to not have set semantics.

Any comments?

=============================
Hibernate version: 3.1.3

Mapping documents:

Facility.hb.xml:
<hibernate-mapping>

<class name="alex.Facility" table="FP_FACILITY">
<id name="fpID" column="FP_ID">
<generator class="native"/>
</id>

<property name="facilityID" type="string" column="FACILITY_ID"/>

<bag name="contacts" inverse="true">
<key column="FP_ID"/>
<one-to-many class="alex.Contact" />
</bag>

<bag name="eus" inverse="true">
<key column="FP_ID"/>
<one-to-many class="alex.EU" />
</bag>
</class>
</hibernate-mapping>

Contact.hb.xml:
<hibernate-mapping>

<class name="alex.Contact" table="FP_CONTACT">
<id name="contactID" column="CONTACT_ID">
<generator class="native"/>
</id>

<property name="contactName" type="string" column="CONTACT_NAME"/>

<many-to-one
name="facility"
column="FP_ID"
class="alex.Facility"
not-null="true"/>
</class>

</hibernate-mapping>


EU.hb.xml:

<hibernate-mapping>

<class name="alex.EU" table="FP_EU">
<id name="euID" column="EU_ID">
<generator class="native"/>
</id>

<property name="euDesc" type="string" column="EU_DESC"/>

<many-to-one
name="facility"
column="FP_ID"
class="alex.Facility"
not-null="true"/>
</class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 1:37 am 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
Have you tried to use:
Code:
        q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);


?

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 2:20 am 
Newbie

Joined: Mon May 29, 2006 12:57 am
Posts: 11
Location: india
Hi agherardi,

U can't use lists or bags as a substitute for set. Bags or lists allow duplicates as well as null values which might hamper you.

As far as i understand from ur hbm file for contacts, contact_id is a primary key. Hope the same is the primary_key in the table. In that case, you should not be having the same contact_id saved more than once in the table. Verify ur schema.

Otherwise, instead of initalising the collection in the facility bean while retrieving it, u an fire a query like "select unique contact_id from contacts" and then set this list to the facility bean's list. Ur problem of duplicates should be resolved in this.

Another way of doing it is to use filters.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 2:22 am 
Newbie

Joined: Mon May 29, 2006 12:57 am
Posts: 11
Location: india
[quote="pradyut"]Hi agherardi,

U can't use lists or bags as a substitute for set. Bags or lists allow duplicates as well as null values which might hamper you.

As far as i understand from ur hbm file for contacts, contact_id is a primary key. Hope the same is the primary_key in the table. In that case, you should not be having the same contact_id saved more than once in the table. Verify ur schema.

Otherwise, instead of initalising the collection in the facility bean while retrieving it, u an fire a query like "select unique contact_id from contacts" and then set this list to the facility bean's list. Ur problem of duplicates should be resolved in this.

Another way of doing it is to use filters.[/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 2:25 am 
Expert
Expert

Joined: Thu May 26, 2005 9:19 am
Posts: 262
Location: Oak Creek, WI
Hi,

I feel that bags will not duplicate, if you dont have duplicate child objects in the list.

Because when you use bag, hibernate deletes all the child and insert a new set of child every time. So its a Costly process.

All the Best

_________________
RamnathN
Senior Software Engineer
http://www.linkedin.com/in/ramnathn
Don't forget to rate.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 2:28 am 
Newbie

Joined: Mon May 29, 2006 12:57 am
Posts: 11
Location: india
Exactly,

Thats the reason why u need to make sure that the collection coming up won't have duplicates if you are using bags or lists.

Hence, Sets are always preferred to Bags except in certain conditions.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 4:46 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
ramnath wrote:
Because when you use bag, hibernate deletes all the child and insert a new set of child every time.


not true.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 5:37 am 
Newbie

Joined: Mon May 29, 2006 12:57 am
Posts: 11
Location: india
Hi Ramnath,

I dont think hibernate will try creating the set again. I have used bags extensivley and havent found such an occurence nor am i facing any overhead which might be an issue in case hibernate tried creating the list again.

The only thing we need to make sure is that the list itself doesn't contain any duplicates....which might be the result of a bad schema.

Let me know if i m wrong.

Any comments????


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 5:44 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
you are join fetching on two collections resulting in a cartesian product and thus duplicate elements is returned - a bag cannot tell which of those elements are real or fake.

This is why hibernate 3.2 will not allow you to run such query any longer (it will tell you only one bag can be fetch at the time)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 5:52 am 
Newbie

Joined: Mon May 29, 2006 12:57 am
Posts: 11
Location: india
In that case, you can remove the join and try to fill up the collections manually,
Otherwise there should be a way of specifying unique="true" kind of a scenarion for the bag.

Max, please advce..


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 29, 2006 5:55 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
bag can contain duplicates and you should not join fetch two of them at the same time....it's that simple ;)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 30, 2006 11:59 pm 
Newbie

Joined: Sun May 28, 2006 2:42 pm
Posts: 14
Thanks to everybody for their replies. Just a few considerations:
- If I join-fetch on one association only, e.g.,

Facility facility = (Facility)session.createCriteria(Facility.class)
.setFetchMode("eus", FetchMode.JOIN)
.add(Restrictions.idEq(pk))
.uniqueResult();

then force Hibernate to initialize the other association with:

Hibernate.initialize(facility.getContacts());

the bag - aka java.util.List - facility.getContacts() contains no duplicates, as correctly indicated by Max. However, this approach requires an additional SELECT

- When join-fetching on two associations at the same time, the duplicate elements in the java.util.List point to the same Contact objects. In other words, Hibernate instantiates a single Contact object for every row in the FP_CONTACT table, however it inserts multiple references to the same Contact objects in the java.util.List. I'm not surprised that Hibernate instantiates a single Contact for every row in FP_CONTACT - Hibernate guarantees uniqueness of entities in its first-level cache. When processing the result of the join, if - for every Contact object - Hibernate could also check if a reference to the Contact is already on the List, and only add the reference to the List if the reference is not already there, this would eliminate the duplicate problem. In other words, this would give us a bag with set semantics, as mentioned in "Hibernate in action" on page 231.

(The reason I would like to map collections to java.util.List's rather than java.util.Set's is that my GUI is JSF-based, and JSF data-driven components take List's, not Set's)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 08, 2006 1:56 pm 
Newbie

Joined: Sun May 28, 2006 2:42 pm
Posts: 14
Max,
With reference to your comment:

> This is why hibernate 3.2 will not allow you to run such query any
> longer (it will tell you only one bag can be fetch at the time)

It would be nice if Hibernate provided a bag-with-no-duplicates collection. A bag-with-no-duplicates behaves exactly like a set, except that implements java.util.List. Multiple associations could be join-fetched with a single select. Applications that need java.util.List collections (e.g., those built around JSF) wouldn't have to convert sets into lists and vice-versa.

Any thoughts?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 09, 2006 2:41 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
there is no such thing in standard java collection api.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 09, 2006 9:14 am 
Newbie

Joined: Sun May 28, 2006 2:42 pm
Posts: 14
Max,

> there is no such thing in standard java collection api.

Provided that the implementation - org.hibernate.collection.PersistentSomething class - took care of checking for duplicates, a java.util.List could be used. E.g.:

public boolean add(Object object)
{
if list already contains object return false
else add object to list and return true
}

public Object set(int index, Object object)
{
if list[index] equals object return object
if list contains object throw exception
add obejct to list
return object
}

In other words, just because a java.util.List can contain duplicates it doesn't have to. A similar rationale is used for mapping a Hibernate bag to a java.util.List: bags are unordered collections, java.util.List's are ordered collections, Hibernate stores bag elements into a java.util.List, without guaranteeing that the order will be maintained.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 31 posts ]  Go to page 1, 2, 3  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:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.