-->
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.  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: List contains unexpected null element
PostPosted: Wed Sep 14, 2005 9:33 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
I have a Product class which contains a List of ProductAttribute objects. The Product class maps to the 'product' table in MySQL and ProductAttribute to 'product_attribute'. On a couple of Products, when I call product.getAttributes, for some mysterious reason the list returned by Hibernate contains 3 elements, one of which is null, instead of the 2 elements it should contain. (There are only 2 matching rows). When I use a Set instead of a List, there is no problem. What's happening with Lists here and how can I correct it? Hibernate 2.1.8, MySQL 4.11. product.hbm.xml below:



<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping
auto-import="false"
>
<class
name="testing.om.Product"
table="`product`"
dynamic-update="true"
dynamic-insert="true"
select-before-update="true"
optimistic-lock="dirty"
>

<id
name="id"
column="`id`"
type="java.lang.Long"
unsaved-value="null"
>
<generator class="native">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Product.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>

<discriminator
column="`discriminator`"
type="string"
/>

<many-to-one
name="department"
class="testing.om.Department"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="`department_id`"
/>

<many-to-one
name="shop"
class="testing.om.Shop"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="`shop_id`"
/>

<property
name="code"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="`code`"
length="10"
not-null="true"
/>

<property
name="keywords"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="keywords"
length="255"
/>

<many-to-one
name="productType"
class="testing.om.ProductType"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="`product_type_id`"
not-null="true"
/>

<list
name="attributes"
lazy="true"
inverse="true"
cascade="all-delete-orphan"
>

<key
column="`product_id`"
>
</key>

<index
column="`index_column`"
/>

<one-to-many
class="testing.om.ProductAttribute"
/>

</list>

<set
name="stockItems"
lazy="true"
inverse="false"
cascade="all-delete-orphan"
sort="unsorted"
>

<key
column="`product_id`"
>
</key>

<one-to-many
class="testing.om.StockItem"
/>

</set>

<many-to-one
name="category"
class="testing.om.Category"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="`category_id`"
/>

<set
name="images"
lazy="true"
inverse="false"
cascade="all-delete-orphan"
sort="unsorted"
>

<key
column="`product_id`"
>
</key>

<one-to-many
class="testing.om.ProductImage"
/>

</set>

<property
name="defaultPrice"
type="java.lang.Double"
update="true"
insert="true"
access="property"
column="`default_price`"
/>

<property
name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="`name`"
/>

<property
name="description"
type="text"
update="true"
insert="true"
access="property"
column="`description`"
/>

<property
name="systemData"
type="java.lang.Boolean"
update="true"
insert="true"
access="property"
column="`system_data`"
/>

<property
name="createdBy"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="`created_by`"
/>

<property
name="lastModifiedBy"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="`last_modified_by`"
/>

<property
name="createdDate"
type="timestamp"
update="true"
insert="true"
access="property"
column="`created_date`"
/>

<property
name="modifiedDate"
type="timestamp"
update="true"
insert="true"
access="property"
column="`modified_date`"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Product.xml
containing the additional properties and place it in your merge dir.
-->

</class>

</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 10:16 am 
Beginner
Beginner

Joined: Thu Jun 02, 2005 5:09 am
Posts: 22
Today I encountered a similar issue in my application: we have defined a Filter on a parent-child relation that is mapped as a bi-directional list.

If a regular query would return all children (for instance, with indices 0 to 6), and the filter causes two of the children to be filtered out, then Hibernate returns a List of size seven with two null entries (for instance, "0, 1, 2, null, null, 5, 6") instead of a List of size five (containing "0, 1, 2, 5, 6").

I don't know if this behaviour is by design and thus a 'feature' of Hibernate, but I would really like to be able to tell Hibernate to leave out the nulls and return a List with 5 consecutive entries. Does anybody know what would be the best way to achieve this? I don't want to insert the non-null items manually into a new List after every query, but I also don't want my Lists to contain nulls.

Joris


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 10:19 am 
Beginner
Beginner

Joined: Tue Aug 16, 2005 11:06 pm
Posts: 46
Here is the exerpt from 3.05 reference doc P82 about bidirectional association:

one-to-many
set or bag valued at one end, single-valued at the other
many-to-many
set or bag valued at both ends

You may specify a bidirectional many-to-many association simply by mapping two many-to-many associations to the same database table and declaring one end as inverse (which one is your choice, but it can not be an indexed
collection
)


You cannot use indexed collection on the many end.

Hope this helps.

_________________
Jason Li
Don't forget to rate:)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 10:25 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
Jason Zhicheng Li wrote:
Here is the exerpt from 3.05 reference doc P82 about bidirectional association:.


I'm using Hibernate 2.1.8, not 3.x. The same thing applies to version 2, though, but it's not the problem in this case. I changed to 'inverse="false"' and still got the same result.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 10:57 am 
Beginner
Beginner

Joined: Tue Aug 16, 2005 11:06 pm
Posts: 46
Is this helpful?

http://forum.hibernate.org/viewtopic.ph ... pty+collec

Good luck

_________________
Jason Li
Don't forget to rate:)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 11:25 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
Jason Zhicheng Li wrote:


Potentially helpful, yes, if it is suggesting (as it seems to be) that incorrect values in the index column might cause null elements to be returned in the list. The problem is that I have seen very little documentation on the use of Lists in Hibernate, so I'm not sure how this index column should get populated. If there were some good examples somewhere it would help. I need to use a List because I need the indexing for Struts.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 11:38 am 
Beginner
Beginner

Joined: Thu Jun 02, 2005 5:09 am
Posts: 22
Jason Zhicheng Li wrote:
<SNIP>
You cannot use indexed collection on the many end.

Hope this helps.


No, that's not entirely correct. When not using inverse="true" on the parent side, this wil work in Hibernate 3. Gavin King confirmed this in a thread related to my question on this kind of mappings:
http://forum.hibernate.org/viewtopic.php?t=943384

BTW, I strongly suspect that this has nothing to do with the fact that I used a mapping that's bi-directional. The issue is that Hibernate creates a List of size 7, probably based on the max index of all returned elements, and uses the index of the children to fill it, while the filtered query only returns 5 elements. When a filter is applied to the query, the maximum index of the returned elements does not always repesent the number of elements + 1 in the resulting List.

Receiving a List which has null-entries and whose size() is not representing the actual number of found instances is really annoying. (and hopefully a bug, so it can be fixed, and not a feature...)

If this is how Hibernate is supposed to work, can anybody please explain the rationale behind the current implementation?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 11:43 am 
Beginner
Beginner

Joined: Thu Jun 02, 2005 5:09 am
Posts: 22
Oh, BTW: the index of my child elements is set correctly in the database. The results I'm getting are not caused by a faulty index...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 11:59 am 
Beginner
Beginner

Joined: Tue Aug 16, 2005 11:06 pm
Posts: 46
Quote:
No, that's not entirely correct. When not using inverse="true" on the parent side, this wil work in Hibernate 3. Gavin King confirmed this in a thread related to my question on this kind of mappings:
http://forum.hibernate.org/viewtopic.php?t=943384


Thanks for the comment. I should have stated it clearly. What I really wanted to say is: The indexed collection limitation applies to bidirectional only. If you do not set inverse="true", the association is no longer bidrectional.

_________________
Jason Li
Don't forget to rate:)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 12:21 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Actually that is not true. Check the HB 3.1 docs.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 12:30 pm 
Beginner
Beginner

Joined: Tue Aug 16, 2005 11:06 pm
Posts: 46
Thanks Gavin. Is that true for H3.0.5?

_________________
Jason Li
Don't forget to rate:)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 12:32 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
The only difference is in the documentation.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 6:07 pm 
Beginner
Beginner

Joined: Thu Jun 02, 2005 5:09 am
Posts: 22
[quote="jkuipers]The issue is that Hibernate creates a List of size 7, probably based on the max index of all returned elements, and uses the index of the children to fill it, while the filtered query only returns 5 elements. When a filter is applied to the query, the maximum index of the returned elements does not always repesent the number of elements + 1 in the resulting List.

Receiving a List which has null-entries and whose size() is not representing the actual number of found instances is really annoying. (and hopefully a bug, so it can be fixed, and not a feature...)

If this is how Hibernate is supposed to work, can anybody please explain the rationale behind the current implementation?[/quote]

Allow me to answer my own question: after thinking this through a little, it isn't that strange: when I navigate a list association, Hibernate only has the position of the elements in the list available to keep track of the index of each element. There's nothing in the objects themselves to indicate their index. Therefore, if the null entries wouldn't be present, duplicate indices would be generated: (0, 1, null, 3) would collapse to (0, 1, 2) while there already is a row with index 2, it's just not present in the current List because a Filter is active. So, the list has to have nulls.

I'm wondering if the current behaviour is intentional, though: looking at the code for PersistentList, it seems that a problem might arise if the last element(s) is/are filtered: then there won't be any trailing nulls (i.e., a list like [0, 1, 2, null, null]) because the nulls are only inserted for padding when adding an element with an index that's higher than the current size of the List... I would have to write a unit test to see if this would actually cause a problem, but I can image that it does: for instance, wouldn't this last example (last two elements filtered out) cause the foreign key to the parent to be nulled for the last two elements, since they're not present in the filtered collection? When the mapping uses cascade="all-delete-orphan", that might even mean that the children would be deleted after Hibernate flushes a dirty, filtered collection...

Joris


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 6:14 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I would personally never put a filter on a List. Doesn't really make sense.

Use a Map or Set if that is what you want.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 1:36 pm 
Newbie

Joined: Sat Jan 29, 2005 7:09 am
Posts: 11
I've just experienced the same problem with Filter in conjunction with a list - and it is very frustrating.

I am using a property called 'obsolete' on all of my mapped classes, and
I simply add a filter 'notObsolete' with condition 'obsolete = 0' on the collection mappings.

When I use a set all this works fine, but a list blows up because Hibernate inserts a null in place of any obsolete objects.

I am in agreement with jkuipers. The best outcome from my perspective would be for Hibernate to return a shorter list without the nulls. However, at the very least Hibernate should not allow filters to be used in conjunction with lists if this is what happens?


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