views:

604

answers:

3

Hi

This is a design pattern question. Here is the scenario: I am using EJB3.0 with JPA. For example lets say I have a user who can belong to groups. So in my User entity I have a method getGroups() which fetches the groups lazily. And I have a UserDao which is a stateless session bean which has a method
User getUser(int uid)

Now in my JSF backing bean I inject the remote interface of UserDao and call getUser on it to get the User bean. But I cannot access user.getGroups because it is a detached entity. So I can think of three approaches here:

  1. In my dao method I eagerly fetch the groups also so that they are accessible in the remote User entity also. But issue with this is Group itself might have lazily fetched relation and those also I will have to eagerly fetch and those might have more lazily fetched relation and so on. So I will end up sending a heavy weight object most of whose properties I will not need.
  2. I send User as it is and rely on my client to not call getGroups on it. I can provide a separate method in userdao which is
    List<Integer> getGroupsIds(int userId)
    And I have a GroupDao which has similar methods getGroup(int groupId) and other methods to get Ids of lazy relations.

  3. Third option is to not send these JPA entities across at all and create other POJOs like UserInfo,GroupInfo etc that just contains the basic attributes of each entity and send these across. And I can have methods in DAOs to get these entities for different relations like:
    List<GroupInfo> getGroupsForUser(int uid)
    List<UserInfo> getUsersInGroup(int gid)

So which of these is a preferred pattern. Or is there some other pattern that people use here?

A: 

I have 3rd option on my current project already implemented. It is not good. Every time you have to change 2-3 classes instead of just one. Fields are duplicated and so on. Not an option.

If you really don't need all the information that User object can eagerly fetch than go with 2nd option.

If it will turn out that in fact all the time you need all the User information. And no one else use your User object via remote service, then use your User object -- go with 1st.

Another solution somewhere there. I need the better one too.

Mykola Golubyev
The problem with 2nd approach is that I am relying on my client to make the right calls which is dangerous. Client would not know that it is not supposed to call getGroups.
Vikas Kedia
remove getGroups() from public access.
Mykola Golubyev
I think it is where JPA (hibernate) stuck. Sounds great but in practice you can't use any of the cool feature.
Mykola Golubyev
+1  A: 

There are also 4th and 5th options :-)

4) Include an "inflation level" parameter on relevant API calls, e.g. getUser(id, inflationLevel). You will thus delegate the responsibility for choosing what parts of object sent over the wire will be available to the client that will use that object. You can have said invlation level as coarse or fine grained as you want. A typical example would be something like BASIC(only immediate properties are populated), ASSOCIATIONS (basic + direct collections / associations), FULL (entire hierarchy - all associated objects).

5) You can write you own proxy that would support over-the-wire lazy initialization. This approach is only feasible if associated objects (or properties) you're lazy loading can potentially be huge but are used (by clients) relatively rarely.

Then, of course, there's also Seam as skaffman mentioned :-)

ChssPly76
A: 

Why User instance is detached? If you are really using JPA, you can use alive instance. So, when getGroups() will be invoked, user groups are loaded lazily.

serge_bg
It is detached because in EJB container managed transaction, transaction ends when you exit the EJB method thus destroying the persistent context and detaching all the entities managed by it.
Vikas Kedia
It depends. Just a small cite from documentation: "In Java EE environments, the jta-data-source and non-jta-data-source elements are usedto specify the global JNDI name of the JTA and/or non-JTA data source to be used by the persistenceprovider."
serge_bg