-->
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: How make a reference in a POJO read-only?
PostPosted: Thu Mar 06, 2008 11:08 am 
Newbie

Joined: Fri Mar 02, 2007 6:31 am
Posts: 19
How can I make a POJO that's referenced in another POJO read-only?

Take this situation:
Code:
public class Level1 {
  int id;
  Level2 level2;
  // necessary getters/setters and annotations
}
public class Level2 {
  int id;
  Level3 level3;
  // necessary getters/setters and annotations
}
public class Level3 {
  int id;
  int value;
  // necessary getters/setters and annotations
}

I get a 'Level1' object from database, set Level1.level2.level3 to null:
Code:
Level1 level1 = (Level1) session.createQuery("from Level1 l where l.level1id = 1").uniqueResult();
Level2 level2 = level1.getLevel2();
level2.setLevel3(null);

result: POJO 'Level2' is updated and I don't want that.

If I use session.createQuery("...").setReadOnly(true).uniqueResult() then the 'Level1' POJO is protected but not any dependent objects.

If I try session.setReadOnly(level2, true) I get an exception: org.hibernate.TransientObjectException: Instance was not associated with the session


So, how can I make dependent objects read-only?



(Note: In our production code we use Session.clear() at the end of the method in which we have manipulated our POJOs to discard any changes we may have made. This method might be called from other methods that may change the POJO even further.
This approach works in Hibernate 3.2.3 but not in any higher version. We're getting a org.hibernate.LazyInitializationException: could not initialize proxy - no Session. Apparently it is suppose the be that way (link to bug report). Thus, it's a bug in the older versions. This is really bad because we created a lot of code that relies on the clear()-method.)


Top
 Profile  
 
 Post subject: Re: How make a reference in a POJO read-only?
PostPosted: Thu Mar 06, 2008 11:17 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
How about evicting level2 after your done?



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 07, 2008 7:42 am 
Newbie

Joined: Fri Mar 02, 2007 6:31 am
Posts: 19
Ah, almost there. The suggestion to use Session.evict(Object) was a good one. However there are some cases where there still is an update.

I modified the test to illustrate it:
Code:
public class Level2 {
  int id;
  Level3 level3;
  Set<Other> otherSet;
  // necessary getters/setters and annotations
}
public class Other {
  int id;
  Level2 level2;
  // necessary getters/setters and annotations
}

The test will go like this:
Code:
Level1 level1 = (Level1) session.createQuery("from Level1 l where l.level1id = 1").uniqueResult();
Level2 level2 = level1.getLevel2();
level2.setLevel3(null);
level2.setAnothers(null);
session.evict(level2);

This will update the 'Other' table:
Quote:
Hibernate: update hibernate_test.other set level2id=null where level2id=?


A solution is to table the set, loop through the items and evict them too:
Code:
...
Set<Another> anotherSet = level2.getAnothers();
level2.setLevel3(null);
level2.setAnothers(null);       
for (Another another : anotherSet) {
  session.evict(another);
}
...


That's a bit inconvenient. I thought org.hibernate.annotations.CascadeType.EVICT could be a better option but I don't know how to use it.

Do you have some pointers?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 07, 2008 10:12 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
Umm, I would say you put it in the relation's cascade and try. It should work. Have you done this already?


Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 10, 2008 3:31 am 
Newbie

Joined: Fri Mar 02, 2007 6:31 am
Posts: 19
It doesn't seem to work. I added it to 'Level2', 'Other' and to both but none worked. I must be doing something wrong.

Level2:
Code:
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Cascade(org.hibernate.annotations.CascadeType.EVICT)
@JoinColumn(name="level2id")
public Set<Other> getOtherSet() {
  return this.otherSet;
}

Other:
Code:
@ManyToOne()
@Cascade(org.hibernate.annotations.CascadeType.EVICT)
@JoinColumn(name = "level2ID")
public Level2 getLevel2() {
  return this.level2;
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 10, 2008 10:47 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
This is weird because my tests pass with the same configuration. So I guess it has something to do with the sequence and if the data is being fetched at a later point. You really need to go into deepest log levels and see what your system is doing.



Farzad-


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.