-->
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.  [ 6 posts ] 
Author Message
 Post subject: List loading seems to be broken
PostPosted: Tue Feb 14, 2006 3:55 pm 
Newbie

Joined: Sun Nov 13, 2005 7:36 am
Posts: 6
I have a hierarchy of classes:

Code:
public class A implements Serializable {
    private Long id;
    private List<B> b;
//..
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public List<B> getB() {
        return B;
    }
//..
}

public class B implements Serializable {
    private Long id;
    private List<C> c;
//..
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public List<C> getC() {
        return C;
    }
//..
}

public class C implements Serializable {
    private Long id;
    private List<String> s;
//..
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public List<String> getS() {
        return s;
    }
//..
}



Now, if I save and load the hierarchy that has more than one B like this:
Code:
em.persist(a);
A loadedA = em.find(A.class, a.getId());
assertEquals(a.getB().size(), loadedA.getB().size());


then if there's more then one entry of C then loadedA has some duplicates of B. I.e test fails with message "Expected <1>, but was <3>.

There's no duplicate entries in the table. Also, I tried manually execute SQL which I got from show_sql=true, and it gets just one entry, as expected.

I thought that it may be a variant of the famous 'equals' problem with the collections, so I tried this quick cheat on B:
Code:

    public int hashCode() {
        return 1;
    }
   
    public boolean equals (Object obj) {
        return true;
    }



But I still get duplicates of B in the list. And actually always as many as many C entries has a B (well, this may be just a coincidence).

I've tried this with both JBoss 4.0.3SP1 and 4.0.4RC1, and have the same result.

If I use a 'Set' instead of a 'List', then of course I get no duplicates. But it's no solution, as I need to persist the order.

Any suggestion how to get rid of duplicate entries?


Top
 Profile  
 
 Post subject: Reproduced
PostPosted: Wed Feb 15, 2006 11:48 am 
Newbie

Joined: Wed Feb 15, 2006 10:39 am
Posts: 6
I was able to reproduce the bug even with simplier C:

Code:
public class C implements Serializable {
    private Long id;
    private String value;
    //...

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}


I.e, no list required there to show the bug. 2 level of lists is enough.

Also in the log it says that 2 Collections were found, but then it loads 4! Well, of course 2 of them are just duplicate entries.

Shall we create a JIRA entry for this?

Name and version of the database: HSQL shipped with JBoss 4.0.4RC1

The generated SQL (show_sql=true):
select a0_.id as id1218_2_, blist1_.A_id as A1_4_,
b2_.id as BList2_4_, b2_.id as id1219_0_,
clist3_.B_id as B1_5_, c4_.id as CList2_5_, c4_.id as id1220_1_, c4_.value as value1220_1_ from A a0_
left outer join A_B blist1_ on a0_.id=blist1_.A_id
left outer join B b2_ on blist1_.BList_id=b2_.id
left outer join B_C clist3_ on b2_.id=clist3_.B_id
left outer join C c4_ on clist3_.CList_id=c4_.id where a0_.id=?;

Debug level Hibernate log excerpt:

16:40:21,123 INFO [STDOUT] Hibernate: select a0_.id as id1234_2_, blist1_.A_id
as A1_4_, b2_.id as BList2_4_, b2_.id as id1235_0_, clist3_.B_id as B1_5_, c4_.i
d as CList2_5_, c4_.id as id1236_1_, c4_.value as value1236_1_ from A a0_ left o
uter join A_B blist1_ on a0_.id=blist1_.A_id left outer join B b2_ on blist1_.BL
ist_id=b2_.id left outer join B_C clist3_ on b2_.id=clist3_.B_id left outer join
C c4_ on clist3_.CList_id=c4_.id where a0_.id=?
16:40:21,123 DEBUG [AbstractBatcher] about to open ResultSet (open ResultSets: 0, globally: 0)
16:40:21,123 DEBUG [Loader] result row: EntityKey[my.test.dmo.B#1], EntityKey[my.test.dmo.C#1], EntityKey[my.test.dmo.A#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.A.BList#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.B.CList#1]
16:40:21,123 DEBUG [Loader] result row: EntityKey[my.test.dmo.B#1], EntityKey[my.test.dmo.C#2], EntityKey[my.test.dmo.A#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.A.BList#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.B.CList#1]
16:40:21,123 DEBUG [Loader] result row: EntityKey[my.test.dmo.B#2], EntityKey[my.test.dmo.C#3], EntityKey[my.test.dmo.A#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.A.BList#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.B.CList#2]
16:40:21,123 DEBUG [Loader] result row: EntityKey[my.test.dmo.B#2], EntityKey[my.test.dmo.C#4], EntityKey[my.test.dmo.A#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.A.BList#1]
16:40:21,123 DEBUG [Loader] found row of collection: [my.test.dmo.B.CList#2]
16:40:21,123 DEBUG [AbstractBatcher] about to close ResultSet (open ResultSets:1, globally: 1)
16:40:21,123 DEBUG [AbstractBatcher] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:40:21,123 DEBUG [ConnectionManager] aggressively releasing JDBC connection
16:40:21,123 DEBUG [ConnectionManager] releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
16:40:21,123 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.B#1]
16:40:21,123 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.B#1]
16:40:21,123 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.C#1]
16:40:21,123 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.C#1]
16:40:21,123 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.A#1]
16:40:21,123 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.A#1]
16:40:21,123 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.C#2]
16:40:21,138 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.C#2]
16:40:21,138 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.B#2]
16:40:21,138 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.B#2]
16:40:21,138 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.C#3]
16:40:21,138 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.C#3]
16:40:21,138 DEBUG [TwoPhaseLoad] resolving associations for [my.test.dmo.C#4]
16:40:21,138 DEBUG [TwoPhaseLoad] done materializing entity [my.test.dmo.C#4]
16:40:21,138 DEBUG [CollectionLoadContext] 1 collections were found in result set for role: my.test.dmo.A.BList
16:40:21,138 DEBUG [CollectionLoadContext] collection fully initialized: [my.test.dmo.A.BList#1]
16:40:21,138 DEBUG [CollectionLoadContext] 1 collections initialized for role: my.test.dmo.A.BList
16:40:21,138 DEBUG [CollectionLoadContext] 2 collections were found in result set for role: my.test.dmo.B.CList
16:40:21,138 DEBUG [CollectionLoadContext] collection fully initialized: [my.test.dmo.B.CList#1]
16:40:21,138 DEBUG [CollectionLoadContext] collection fully initialized: [my.test.dmo.B.CList#2]
16:40:21,138 DEBUG [CollectionLoadContext] 2 collections initialized for role: my.test.dmo.B.CList
16:40:21,138 DEBUG [StatefulPersistenceContext] initializing non-lazy collections
16:40:21,138 DEBUG [Loader] done entity load
16:40:21,138 INFO [STDOUT] loadedA.getB:4


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 16, 2006 11:13 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
this has been answered many times

_________________
Emmanuel


Top
 Profile  
 
 Post subject: Isn't this against EJB3 spec?
PostPosted: Thu Mar 02, 2006 8:40 am 
Newbie

Joined: Wed Feb 15, 2006 10:39 am
Posts: 6
emmanuel wrote:
this has been answered many times


Yes, but not in relation to EJB3. The EJB3 draft doesn't explicitly say anything about allowing duplicate entries during eager loading. I think therefore it would be natural to assume they are not allowed. I absolutely agree that in sake of performance it would be possible to load duplicate entries in some queries. But not in the case of loading by Id like this:
Code:
A loadedA = em.find(A.class, itemId)

In this case I think it would be natural to expect getting the hierarchy exactly the way it was before persisting it? Am I wrong?

Something has to be changed either in EJB3 spec, or in Hibernate, because currently there's no way to get rid of duplicated entries during eager loading, unless Hibernate-specific extensions (e.g. @IndexColumn) are used.

Or do I misunderstand the purpose of the "find" method in the EntityManager?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 02, 2006 8:14 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Use Sets

_________________
Emmanuel


Top
 Profile  
 
 Post subject: And how to preserve order?
PostPosted: Fri Mar 03, 2006 1:14 pm 
Newbie

Joined: Wed Feb 15, 2006 10:39 am
Posts: 6
emmanuel wrote:
Use Sets


And if I need to restore a collection keeping the order of the elements it had before the persistence?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

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.