Seam Managed Persistence Contexts

From Shrubbery

(Redirected from Session-in-view with Seam)
Jump to: navigation, search


Enabling the equivalent of 'session-in-view' with Seam

[edit] Overview

Seam comes with some built in components that support the 'session-in-view' pattern: Seam Managed Persistence Contexts. Actually it's much more correct than the 'session-in-view' pattern, but that's besides the point. Seam-managed persistence contexts can be used to eliminate lazy initialization exceptions when evaluating JSTL-EL expressions during view rendering as well as to bind all the activity in a conversation together under a single optimistic transaction.

See the docos here: http://docs.jboss.com/seam/latest/reference/en/html/persistence.html


There are a few subtle things that this doesn't explicitly cover:

  1. You can use the Seam-managed EntityManager in EJBs - This will eliminate some of the need for using merge(obj) because the EJBs can use the conversational EntityManager. However, in cases where you have a transaction-scoped EntityManager you will still need to merge or load objects that came from a different EntityManager.
  2. The Seam Application Framework classes are designed to use Seam-managed transactions

[edit] Steps

  1. Enable the TransactionalSeamPhaseListener in faces-config.xml
        <lifecycle>
            <!--
            We use the extended persistence context because we're going to take advantage of
            persistence contexts (hibernate sessions) that are conversation scoped (span transactions).
            This matches what the user may think is a "transaction", but in reality it may be many
            underlying database transactions.
            -->
            <phase-listener>org.jboss.seam.jsf.TransactionalSeamPhaseListener</phase-listener>
        </lifecycle>
    
  2. Enable a Seam-managed persistence context in components.xml
        <core:transactionListener/>
    
        <core:managed-persistence-context name="entityManager"
                                          auto-create="true"
                                          persistence-unit-jndi-name="java:/EntityManagerFactories/myDb"/>
    

    Assuming you have a persistence.xml something like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence">
        <persistence-unit name="myDb">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>java:/MyDataSource</jta-data-source>
            <properties>
                <!-- Register the entity manager factory in JNDI so SEAM can use it. -->
                <property name="jboss.entity.manager.factory.jndi.name"
                          value="java:/EntityManagerFactories/myDb"/>
                <!-- Comment this out once we switch to true migration -->
                <!--<property name="hibernate.hbm2ddl.auto" value="create"/>-->
                <property name="hibernate.show_sql" value="false"/>
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
                <property name="com.intellij.javaee.persistence.datasource" value="Mysql local"/>
            </properties>
        </persistence-unit>
    </persistence>
    
  3. Inject the Seam-managed EntityManager into your components using @In (instead of the usual @PersistenceContext), for example:
    @Stateless
    public class MyEJBImpl implements MyEJB
    {
        ...
    
        @In
        private EntityManager entityManager;
        ...
    }
    

[edit] But session-in-view is an anti-pattern, isn't it?

Yes, it is! However what Seam is doing is not really session-in-view. Actually Seam provides two sessions:

  1. A session that exists during the postback phases of JSF.
  2. A separate session used for rendering the next view.

This eliminates the problem with the ordinary session-in-view pattern where the rendering part of the web request cycle affects the persistence context / database transaction done in the controller. Incidentally this is why a session-in-view design should never be used in an enterprise-class application (IMO) because presumably the user thinks their data is actually important and would not like an inconsistent database.

Personal tools