0

I'm wondering: What is the point of FetchType.LAZY in one(many)-to-many using DAO Pattern? It is basically useless? As soon as you are outside of your DAO (eg. were the actual work is done) you can't fetch the related data as you are not in a hibernate session anymore.

Lets make an Example:

Student and Class. A student takes many classes. he now logs into the system and his Student entity object is retrieved from the system.

application layer -> Service Layer -> DAO

Now the Student wants to see which classes he takes and oops a LazyInitializationException occurs as we are outside of DAO.

What are the options to prevent this? I've like googled hours and not found a solution for this except to actually fetch everything before leaving the DAO which defeats the purpose of lazy in the first place. (Have read about OpenSessionViewFilter but this should work independent of the application layer)

How do you solve this issue in a good way? What are alternative patterns that don't suffer from this?

EDIT:

I get no LazyInitializationException with following settings:

@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.compound", 
        cascade = CascadeType.ALL, orphanRemoval = true)
@Fetch(FetchMode.JOIN)

Funny thing is it must be exactly like this.

removing @Fetch -> LazyInitializationException

Even stranger is if I remove orphanRemoval = true, then LazyInitializationException also occurs even with @Fetch. So both of those are required.

Maybe someone could enlighten me why this is the case. Currently I'm tending to ditch hibernate completely as with pure JDBC I would have reached the desired behavior hours ago...

Cezar
  • 52,020
  • 18
  • 84
  • 86
beginner_
  • 6,371
  • 18
  • 60
  • 112

2 Answers2

1

You can always fetch foreign-key relation data without the same ession. Since your session does not exists outside your Application Layer you just fetch it manually in the method where you retrieve the data and set it.

Application Layer:

public List<SchoolClass> getSchoolClassesByStudent(Serializable identifier)
{
    List<SchoolClasses> schoolClasses = // get classes by student using criteria or hql
    return schoolClasses;
}

Client Layer:

public void loadSchoolClassesByStudent(Student student)
{
    student.setSchoolClasses(application.getSchoolClassesByStudent(student.getId()));
}

I myself choosed not to support any collections in my hibernate entities.
I fetch all child relations with very generic methods that my server provides to my client similar to this one.

Edit: Or create some logic (interceptor?) that can check outside the DAO if data is uninitialized before accessing it and initialize it using a generic method.
This would also assume that Hibernate jar's are on the client level, which depends if this is a good idea (Same if the uninitialized data is not set to null).

djmj
  • 5,266
  • 4
  • 47
  • 89
  • But basically you are creating a convention which the developers using your entity classes must follow. I would prefer to have this handled automatically. – beginner_ Oct 08 '12 at 11:18
  • I would also prefer this. But if your Session outside your DAO is not existent, (Basically its a StatelessSession then) I don't see any other way then writing generic initialization methods for your entities, you can call from the outside the DAO (client). Or set uninitialized data to null, and do null checks on the client. Or create some logic that can check outside the DAO if data is uninitialized before accessing it and initialize it using a generic method. – djmj Oct 08 '12 at 11:25
  • Ok accepted this answer. My solution was to load eager from owner to child but not in the reverse. This is no issue as in general the number of children is very small (<3) in the average case. To achieve this I used FetchType.EAGER on owner side. – beginner_ Oct 09 '12 at 12:35
0

One way to solve the problem is to use OpenSessionInViewFilter Filter.

<filter>
    <filter-name>hibernateSessionFilter</filter-name>
    <filter-class>
        org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    </filter-class>
</filter>
Ralph
  • 111,219
  • 48
  • 270
  • 362
  • Isn't this for web app only? My solution should work for any presentation layer. – beginner_ Oct 08 '12 at 11:19
  • @beginner_ you are right, I expected that this is a web application. - Are I am wrong? – Ralph Oct 08 '12 at 11:20
  • No its for a framework for persisting special type of data. So presentation layer can be anything (web or swing or...). That's up to the developer using this. – beginner_ Oct 08 '12 at 12:02
  • @beginner_: In this case you should require the user of your framework to handle Hibernate Session and Transactions right. And of course you should attach an example of how to do it. (At least your framework user has to open an Hibernate session like the OpenSessionInViewFilter does, if the user then user the OpenSessionInViewFilter (if he has a web app) or open it by hand, is completly the users decision.) – Ralph Oct 08 '12 at 12:39
  • Part of the idea is that the user does not need to bother with hibernate but concentrate on the presentation layer. – beginner_ Oct 08 '12 at 14:35
  • @beginner_ If the user use hibernate features (like lazy loading) then he will be come in touch with hibernate. Anyway one should separate the business logic from the infrastructure stuff (and hide them a bit from the user) and this is exactly what OpenSessionInViewFilter does. But in the end, using a database with lazyloding and transactions contains some komplextity that can not be hiden from the user (all frameworks I know that tryed this have be failed in the End.) – Ralph Oct 08 '12 at 14:52
  • Anyway, open session in view is not recommended. http://stackoverflow.com/questions/1103363/why-is-hibernate-open-session-in-view-considered-a-bad-practice – Jay Oct 08 '12 at 15:43
  • @Jay: that strongly depends on your system, and whenever or not to use the OpenSessionInViewFilter is recommended or not, should be an decision of the Software-Architect. – Ralph Oct 08 '12 at 16:13