[JBoss Seam] - Re: EntityManger-per-user-session...
by iradix
I think you're biggest problem is you haven't gotten your head wrapped around the conversational model yet. It definitely takes time and I'd recommend that the first thing you do is at least skim through the Seam reference documentation in it's entirety.
That being said, I'll try to explain as best I can.
anonymous wrote : I don't understand this part at all. I know that if I stick the edited activity back into the users collection of activites and have the correct cascade type, that when I save the updated user, it will save the updated activity as well.
Where you're going wrong here is you don't need to stick the activity back into the list if it's already there. If you are using a conversationally scoped EM (which is what my suggestions are based on) then there will only be one version of each activity per conversation, whether that activity was retrieved through user.getActivities or through SELECT..... That's how an EntityManager works and it's important to understand that. So rather than the view that you provided, what I'm talking about is the edit view where you will have values bound like:
| Name: <h:inputText value="#{selectedActivity.name}"/>
|
When the update data model phase happens the name would be updated on the one and only version of the selected Activity, which is managed by your conversation scoped EM, and when the transaction is commited it will be updated. After that anytime you access user.getActivities() you will see the updated activity and it will be reflected in the database. Does that make more sense?
anonymous wrote : I guess that's what I'm saying. I'm not sure I'd call it spanning more than one conversation. In reality, user is a session scoped bean representing the currently logged in user.
Well, since a session may contain many conversations, then your User object at least has the capability of spanning more than one and that should be factored in. Again, this seems to be an issue with your understanding of how conversations, and more specifically conversation scoped EMs work. You cannot use the @PersistenceContext annotation to specify a conversation scoped EM. It needs to be injected using the @In annotation, and if you've configured that correctly (see the docs on how) Seam will magically make sure that the same EM gets injected into every bean within the same conversation.
As far as persistence units are concerned, I've never had the need to deal with more than one on a project, but I'd imagine if I did I could create 2 Seam managed EMs, one for each persistence context and then your example would become:
| @In(create="true")
| EntityManager manager1;
|
| @In(create="true")
| EntityManager manager2;
|
Where manager1 and manager2 are both properly configured, conversation scoped EMs.
Make more sense?
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3983934#3983934
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3983934
19Â years, 6Â months
[JBoss Seam] - Re: EntityManger-per-user-session...
by bkyrlach
Before I argue with you I want to point out that I like your solution. My argument is just me trying to understand more of what you're saying.
"iradix" wrote : With a proper cascade on the activities list stored within the user, you should be able to just bind the values that are editable via the value attribute of each JSF component.
I don't understand this part at all. I know that if I stick the edited activity back into the users collection of activites and have the correct cascade type, that when I save the updated user, it will save the updated activity as well. However, this has two problems with it.
#1: Iterating through the users activities to find the one who's id matches the activity that's being edited is painful and can consume a lot of resources. If the users collection of activities is 3000 elements big, for example, I'd imagine that this method would take a long time to return.
#2: The activity that's being injected doesn't come from the collection of the users activities. This is from following the booking example, where you have to have a list marked as @DataModel in order to have s:link be able to pull out individual activities to edit. Here's an example to illustrate...
| @DataModel
| List<Activity> activities;
|
| public void getActivitiesForUser()
| {
| activities = em.createQuery("from Activity a where a.user = :user order by a.name").setParameter("user", user).getResultList();
| }
|
and in the view...
| <h:dataTable value="#{activities}" var="tmp">
| <h:column>
| <f:facet name="header">Name</f:facet>
| #{tmp.name}
| </h:column>
| <h:column>
| <f:facet name="header">Date</f:facet>
| #{tmp.date}
| </h:column>
| <h:column>
| <f:facet name="header">Edit</f:facet>
| <s:link value="Edit Activity" action="#{editActivity.editActivity(tmp)}"/>
| </h:column>
| </h:dataTable>
|
"iradix" wrote : After they are validated and the model is updated (i.e. new values are set on each appropriate activity) saving the user at the end of the transaction will update the DB representation of whatever activities have changed. There should be no merging necessary as long as your conversation is long running because they are the same objects from page to page. What could be easier than that?
That's assuming that the user is being managed by the conversations entitymanager. Otherwise, I have to merge user at the start of the editActivity. Again, more code...
| @In(required=false)
| User user;
|
| @Begin
| public String preEditActivity()
| {
| user = em.merge(user);
| this.activity = tmp;
| return "/activity/edit.xhtml";
| }
|
"iradix" wrote : If what you're saying about the UserActions SLSB is that you have a User spanning more than one conversation, try this:
|
|
| | @In(create = true)
| | private EntityManager em;
| |
| | private String userId;
| |
| | public void setUser(User user){
| | this.userId = user.getId();
| | }
| |
| | public User getUser(){
| | return em.find(User.class, userId);
| | }
| |
|
I guess that's what I'm saying. I'm not sure I'd call it spanning more than one conversation. In reality, user is a session scoped bean representing the currently logged in user. In user actions, the user logs in thusly...
| @In(required=false)
| @Out(required=false)
| private User user;
|
| @In(required=false)
| private User newUser;
|
| public String login()
| {
| User temp = (User)manager.createQuery(
| "from User u where u.username = :username and u.password = :password").setParameter(
| "username", user.getUsername()).setParameter("password", user.getPassword()).getSingleResult();
| if (temp != null)
| {
| user=temp;
| return "/activity/viewer.xhtml";
| }
| facesMessages.add("This user does not exist in our database.");
| return Outcome.REDISPLAY;
| }
|
Because this happens in userActions, activityActions extended entitymanager says that the user I inject from the session context is not attached. Of course, it is correct, because that entitymanager wasn't the one that pulled the user from the database.
"iradix" wrote : Seam will make sure the appropriate conversation scoped em is injected into your SLSB on each call so you'll get the same User object every time, as long as you are within the same conversation. No merging necessary. You can even inject it into other beans using @In(value="#{userActions.user}")
I don't understand... how does it know which persistence unit that this EM should be tied to? What if in my conversation scoped activityActions I inject two persistenceContexts thusly...
| @PersistenceContext(unitName="db1")
| EntityManager manager1;
|
| @PersistenceContext(unitName="db2")
| EntityManager manager2;
|
Which one would be injected? I'm confused.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3983930#3983930
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3983930
19Â years, 6Â months