Hi,

> You need to use @SessionState because @Persist is only valid for a given page 
> or component. Page1's @Persist private 
> User user; is stored in a different session attribute than Page2's @Persist 
> private User user;. If you want something 
> persisted across pages, you need to use @SessionState.  
> Being a complex object makes no difference about choosing one annotation or 
> the other.

Because I feared this answer would arrive, I separated my two topics Session 
and Memory into two separate mails :-)

What I meant to say was they recommend @SessionState instead of 
@SessionAttribute because it is a complex object. I never intended to use 
@Persist with the session state objects.

> @SessionState is keyed by type, not by field name, so @SessionState private 
> User user; and @SessionState private User 
> currentUser; will point to the same object, stored in the same session 
> attribute.

Just as I thought, thank you.

> The error isn't related to transactions nor Tapestry at all. It's related to 
> your Hibernate/JPA usage: one entity is loaded in 
> one request, one Hibernate session/JPA entity manager instance. Then, in 
> another request, another session/entity 
> manager instance, you try to load some lazy field.  
> You need to use the merge() method of org.hibernate.Session or EntityManager 
> to reattach the entity to the current 
> Hibernate session or JPA entity manager.

I've since reduced the @SessionState object to a user and removed the 
AppSession object because the login time was never used anywhere anyway. I hate 
it when people program something just because they think someone may need it 
some day.
This of course fixed the bug.

If I'd use the merge() method, I'd have to inject an EntityManager or one of my 
DAO services into my AppSession object.
Or wouldn't this work because my AppSession is not a page or component?
If this wouldn't work, then every time someone would use my AppSession user, he 
would have to get() the user and then do a manual merge() or via DAO on it.

Can I inject into my AppSession object or what would be the way to go here?

Regards,
Daniel P.

-----Ursprüngliche Nachricht-----
Von: Thiago H de Paula Figueiredo [mailto:thiag...@gmail.com] 
Gesendet: Mittwoch, 18. März 2015 14:17
An: Tapestry users
Betreff: Re: Session Storage with Tapestry

On Wed, 18 Mar 2015 07:21:06 -0300, Poggenpohl, Daniel 
<daniel.poggenp...@isst.fraunhofer.de> wrote:

> Hello again,

Hi!

> I need a session storage where I store the currently logged on user.  
> Reading about it in the documentation, they recommend using 
> @SessionState because my user is a complex object, also containing 
> lists of other entities.

You need to use @SessionState because @Persist is only valid for a given page 
or component. Page1's @Persist private User user; is stored in a different 
session attribute than Page2's @Persist private User user;. If you want 
something persisted across pages, you need to use @SessionState.  
Being a complex object makes no difference about choosing one annotation or the 
other.

> My user also is an entity in a database. So, when a user logs in, the 
> appropriate entity is retrieved from the database, an "AppSession"
> object is created containing, among e.g. the time of login, the user 
> object. Is this the right way to do it? Or should I only store the ID 
> in the session?

This is extremely dependent on how you're going to use your user information. 
If you're going to show their name in every page, for example, and you store 
just the id, you'll be querying the database for the same information every 
request (unless you use some kind of cache between your page or component or 
mixin and your database).

> Now when the SessionState object is created, it can be used in any 
> other page or component using the same SessionState annotation and the 
> same type. Does it need to be the same name I'd say it doesn't, as 
> I've not read otherwise.

@SessionState is keyed by type, not by field name, so @SessionState private 
User user; and @SessionState private User currentUser; will point to the same 
object, stored in the same session attribute.

> To do this, a service receives the user. The service tries to access 
> the lazy collection, but fails with a "failed to lazily initialize a 
> collection of role:".
> What I gather from this is, services don't operate within transactions?

The error isn't related to transactions nor Tapestry at all. It's related to 
your Hibernate/JPA usage: one entity is loaded in one request, one Hibernate 
session/JPA entity manager instance. Then, in another request, another 
session/entity manager instance, you try to load some lazy field.  
You need to use the merge() method of org.hibernate.Session or EntityManager to 
reattach the entity to the current Hibernate session or JPA entity manager.

Services operate within transactions as long as you use @CommitAfter 
(tapestry-hibernate or tapestry-jpa) or something like that (other library).

-- 
Thiago H. de Paula Figueiredo
Tapestry, Java and Hibernate consultant and developer
http://machina.com.br

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to