-->
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.  [ 2 posts ] 
Author Message
 Post subject: Hibernate.initialize(...) initializes more than it should
PostPosted: Thu Oct 16, 2008 12:26 pm 
Newbie

Joined: Fri Oct 03, 2008 2:30 am
Posts: 16
Location: Neuchâtel, Switzerland
Hibernate version: 3.2.4 sp1

I got a problem with Hibernate.initialize(...). It actually initializes more than it should.

Setup: A parent child relationship between the entities Model and Revision.
Goal: The collection Model.revs should contain only the latest Revision.
Solution: Use a Filter on Model.revs

Code:
@Entity
@FilterDef(name = "maxRev", parameters = { @ParamDef(name = "modelId", type = "long") }, defaultCondition = "id = (select rev.id from _Revision rev where rev.modelId = :modelId and rev.number = (select max(r.number) from _Revision r where r.modelId = :modelId))")
public class Model
{
  @Id @GeneratedValue
  public Long id;

  @OneToMany(cascade = CascadeType.ALL, mappedBy = "model")
  @Fetch(FetchMode.SUBSELECT)
  @Filter(name = "maxRev")
  public Collection<Revision> revs = new ArrayList<Revision>();
}

@Entity
public class Revision
{
  @Id @GeneratedValue
  public Long id;

  public Integer number;

  @ManyToOne(optional = false)
  @JoinColumn(name = "modelId", nullable = false, updatable = false)
  public Model model;
}

Problem description
All Model's are loaded from the database and each Model's Revision collection should be initialized (filtered), because the entities will be detached and sent to the client.

Code:
List<Model> models = session.createQuery("from Model").list(); // returns 2 Model's
Model m1 = models.get(0);
Model m2 = models.get(1);

System.out.println("m1.revs: " + Hibernate.isInitialized(m1.revs) + ", "
                 + "m2.revs: " + Hibernate.isInitialized(m2.revs));

session.enableFilter("maxRev").setParameter("modelId", m1.id);
Hibernate.initialize(m1.revs);
session.diableFilter("maxRev");

System.out.println("m1.revs: " + Hibernate.isInitialized(m1.revs) + ", "
                 + "m2.revs: " + Hibernate.isInitialized(m2.revs));

The output should be (IMHO) the following (JBoss Server log...)
Code:
m1.revs: false, m2.revs: false
m1.revs: true, m2.revs: false

But for some strange reason (bug?) it is
Code:
m1.revs: false, m2.revs: false
m1.revs: true, m2.revs: true

Of course m2.revs is empty, because is was filtered using the wrong criteria. But why was this collection initialized anyway?

Thanks for any hints,
Ron


Top
 Profile  
 
 Post subject: Reason found...
PostPosted: Fri Oct 17, 2008 11:18 am 
Newbie

Joined: Fri Oct 03, 2008 2:30 am
Posts: 16
Location: Neuchâtel, Switzerland
I found out what the problem is:
I you want to use Hibernate.initialize() to load your lazy loaded collections, it is a bad idea to set @Fetch(FetchMode.SUBSELECT) for these collections.
(In my case the subselect was an relict from the first tests using eager loading).

To illustrate what happens, here the generated SQL Statements (the very last line of each code block shows the difference)

with @Fetch(FetchMode.SUBSELECT):
Code:
Hibernate: select revs0_.modelId as modelId1_, revs0_.id as id1_, revs0_.id as id7240_0_, revs0_.version as version7240_0_, revs0_.uuid as uuid7240_0_, revs0_.name as name7240_0_, revs0_.description as descript5_7240_0_, revs0_.number as number7240_0_, revs0_.modelId as modelId7240_0_ from _Revision revs0_ where  revs0_.id = (select rev.id from _Revision rev where rev.modelId = ? and rev.number = (select max(r.number) from _Revision r where r.modelId = ?)) and revs0_.modelId

in (select model0_.id from _Model model0_)

without @Fetch(FetchMode.SUBSELECT), defaults to FetchMode.JOIN:
Code:
Hibernate: select revs0_.modelId as modelId1_, revs0_.id as id1_, revs0_.id as id6456_0_, revs0_.version as version6456_0_, revs0_.uuid as uuid6456_0_, revs0_.name as name6456_0_, revs0_.description as descript5_6456_0_, revs0_.number as number6456_0_, revs0_.modelId as modelId6456_0_ from _Revision revs0_ where  revs0_.id = (select rev.id from _Revision rev where rev.modelId = ? and rev.number = (select max(r.number) from _Revision r where r.modelId = ?)) and revs0_.modelId

=?


The consequence when using FetchMode.SUBSELECT is, all revision collections of all models are getting initialized, no the one requested.

I don't know if this behavior is defined or not, at least I should be mentioned in the documentation (if it is, I didn't find it).
Maybe in section "19.1.4. Initializing collections and proxies".


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 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.