Hello, jaikiran
Many thanks for posting the tip. I fixed the LazyInitialisationException problem in this
instance. However, I think I am facing a much more general EJB design problem, which I
will try to explain further down.
With regards to the earlier posting, in addition to using merge() before persist(), as you
helpfully suggested, I also had to add this:
@TransactionAttribute(TransactionAttributeType.REQUIRED)
| public void addPublicSubject(Subject s, User u) {
|
| User u = entityManager.merge(user);
| Subject s = entityManager.merge(subject);
|
| u.getSubjectsThisUserSubscribedTo().add(s);
| s.getUsersThatSubscribedToMe().add(u);
|
| entityManager.persist(u);
| entityManager.persist(s);
|
| }
|
Thus, it updates the relationship table (shared_subject in this case)
In addition I modified findSubject(int subjectId) of session bean SubjectBean as follows
| @TransactionAttribute(TransactionAttributeType.REQUIRED)
| public Subject findSubject(int subjectId) {
| Subject s = (Subject)entityManager.find(Subject.class, subjectId);
|
| s.getOwner();
| s.getUpdater();
| Collection<Topic> temp_topics= s.getMyTopics();
| if(!temp_topics.isEmpty()) temp_topics.size();
| Set<User> temp_users = s.getUsersThatSubscribedToMe();
| if(!temp_users.isEmpty()) temp_users.size();
| return s;
| }
|
because I read in one of the tutorials that all relationships must be managed explicitly
in the transactional code.
That is if we want the client to have access to the cmr fields of the Subject they must be
pre-fetched within the transaction by executing seemingly useless statements like
collectionXXX.size() or s.getOwner() even though we donÃÂÃÂÃÂÃÂt assign the result
of such statements to anything and donÃÂÃÂÃÂÃÂt use it within the transaction.
EJB design problem:
So, to avoid LasyInitialisationException CMR Fields first have to be accessed in the
transactional context of a session bean in order to be loaded into the Entity Bean
Suppose, I have a bean User with the following CMR fields:
| Set<Subject> mySubjects;
| Set<Topic> topicsThisUserCreated;
| Set<Entry> entriesThisUserAuthored;
| Set<Topic> topicsThisUserUpdated;
| Set<Topic> entriesThisUserUpdated;
| Set<Subject> subjectsThisUserSubscribedTo;
|
Respectively each object in each collection has CMR fields
|
| Subject:
| User owner;
| User updater;
| Collection<Topic> myTopics;
| Set<User> usersThatSubscribedToMe;
| Topic:
| User creator;
| User updater;
| Subject subject;
| Topic parentTopic;
| private Collection<Topic> nestedTopics;
| private Set<Entry> entries;
|
| Entry:
| private Topic topic;
| private User author;
| private User updater;
| Plus entry has a field:
| private String entryBody; which is @Lob
|
When User is accessed in the detached context (somewhere in the client) technically
speaking it is possible that the client will call something like:
| public void buildOutput(User user, Output out){
| User u = user;
| Set<Subject> ss = u.getSubjectsUserSubscribedTo();
| for(subject:ss) {
| Set<Topic> tt = subject.getMyTopics();
| for(topic:tt) {
| outputTopic(topic, u, out);
|
| }
| }
| public void outputTopic(Topic topic, User u, out) {
|
| if(topic.getParent()!=null) outputTopic(topic.getParent(), u, out);
| out.setElemet(ÃÂÃÂTopic.class.getName());
| out.add(topic.getName);
| out.add(topic.getCreator().getUserName());
| out.add(topic.getUpdater().getUserName();
| out.add(topic.getCreator().getTopicsThisUserUpdated().size());
| Set<Entry> ee = topic.getEntries();
| for(entry:ee){
| out.setElement(Entry.class.getName()ÃÂÃÂ);
| out.add(entry.getName();
| out.add(entry.getAuthor().getUserName());
| out.add(entry.getBody());
| }
| }
|
|
I donÃÂÃÂt think it will work because LazyInitializationException can be thrown in the
dozens of places in this snippet of code.
This poses a design issue:
The getters and setters of CMR fields must be public so that the EJB container could
manage them.
If they are public the client has access to them in the detached context, but to avoid
Lazy Loading Exception they have to be set and accessed in the transactional context of a
session bean.
My understanding is that EJB3 disposed of the Data Transfer and Data Access objects in
order to simplify the EJB model and instead introduced the notion of the detached context
in which Data Access objects (User, Subject, Topic, Entry in this case) act as Data
Transfer Objects as far as client is concerned. However, LazyInitializationException will
always be on the way in this model.
So, the question is how can we ensure that the client doesnÃÂÃÂt access CMR fields
outside of transactional context from the design point of view?
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4147060#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...