Reputation: 484
I have POJO with couple of strings/numbers/... and I want to get only this pojo, without any sub-POJOs in lists/maps/sets that could be attached by hibernate. If I execute query to get first pojo, exception is thrown when someone touches those subobjects.
This is normal behaviour and I agree with this, but is there a way, not to call this:
object.setSomeMap(null);
but to set it for default behaviour? I don't see setting each property like this as best solution as I have quite big model for everything.
Thanks!
Upvotes: 0
Views: 318
Reputation: 6540
Set your FetchType
to FetchType.LAZY
and they won't be loaded when you load your class from the database. I'll give you an example:
@Entity
@Table(name="FOO")
public class Foo{
@Id
@GeneratedValue
@Column
private int id;
@Column
private String prop1;
@Column
private String prop2;
//You don't have to set fetch type like this, as lazy is the default for collections,
//but it doesn't really hurt anything
@OneToMany(fetch=FetchType.LAZY)
private List<Bar> listOfBars;
}
So when you load up your Foo
class, id
, prop1
and prop2
will be loaded and set from the database, but the listOfBars
objects will not be populated.
Whenever you try to access the listOfBars
objects, Hibernate detects it and tries to populate the objects before you can get it. AFAIK if you try and set listOfBars
to null, Hibernate will detect this and try to delete your foreign keys, effectively removing all the members of listOfBars
if you update the object. Eg:
@Transactional
public Foo doStuffWithFoo(int id){
Foo foo = fooDao.find(id);
//Set listOfBars to null so we can't call it.
//This is bad and will cause disaster when we update Foo.
foo.setListOfBars(null);
//Do some stuff with Foo that changes values.
fooDao.saveOrUpdate(foo);
return foo;
}
Because you set your listOfBars
object to null here, AFAIK Hibernate will then delete all your foreign keys because your list doesn't exist any more. Hibernate knows the difference between a list that is empty because it didn't populate it when it created the object and a list that you have set to null/emptied. If the case of the former, it doesn't do anything except perhaps cascade the updated status if it needs to. In the case of the latter, it will clear your associations, possibly deleting Bar objects, if you have orphanRemoval
set to true.
However if you do try to access your listOfBars
once you have returned Foo
out of the method you get another problem. This problem occurs because the @Transactional
session you originally used to fetch your Foo
class has ended before you try to access your listOfBars
. You have 3 options at this point, each with their own problems.
The first option (which is what most people try, and get frustrated because it doesn't work) is you can open a new session, and try to populate your listOfBars
object. Hibernate assumes that both your Foo
object and all the Bar
objects in your listOfBars
could have changed since the transaction was ended (which is perfectly true), so it throws an exception.
Another option is to fetch the entire Foo
object again and populate the listOfBars
object in your new transaction. The problem with this is that its quite inefficient to be doing multiple selects like this.
Your final option is to never try and access your listOfBars
object if you know that its not there. You can't even perform a null check because Hibernate will detect your call to getListOfBars()
and try and populate the object before the null check actually happens.
I have written a Hibernate tutorial for creating object relationships here that you might find helpful. I also discuss things like Lazy vs Eager object fetching for collections as well as a few other Hibernate things that can be helpful when designing classes for use with Hibernate.
Best of luck
Upvotes: 1