TransactionRequiredException with em as producer field
janey Feb 12, 2010 11:41 AMHey all,
I was happy to hear that the bug -- WELD attemps to close the EntityManager Link -- has been fixed with WELD-1.0.1.CR2. So I downloaded the new version and tried again the example from WELD using a producer field for injecting the EM:
@SessionScoped
@Named("login")
@Stateful
public class LoginAction implements Serializable, ILoginActionLocal
{
private static final long serialVersionUID = 1L;
private User user;
@Inject Credentials credentials;
/**
* inject EM
*/
@Inject @BankDatabase EntityManager database; // --> only works once
//@PersistenceContext private EntityManager database; // --> always works fine
/**
*
*/
public void login() {
// logout old user
logout();
user = (User) database.find(User.class, credentials.getUsername());
if(user == null)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
"User does not exist: " + credentials.getUsername()));
return;
}
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Welcome, "
+ credentials.getUsername()));
}
/**
*
*/
public void register() {
User user = (User) database.find(User.class, credentials.getUsername());
if(user != null)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
"User already registered: " + user.getName()
+ ", at date: "+ user.getInsertDate()));
} else
{
user = new User();
user.setName(credentials.getUsername());
user.setInsertDate(new Date());
user.setPassword(credentials.getPassword());
database.persist(user);
database.flush();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
"Welcome, " + credentials.getUsername()));
}
}
/**
*
*/
public void logout() {
user = null;
}
[...]
}
Database producer class:
public class BankDatabaseProducer {
@Produces @BankDatabase @PersistenceContext EntityManager userDatabase;
}
The login form:
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:messages/>
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputText id="password" value="#{credentials.password}"/>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Register" action="#{login.register}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>
</ui:define>
</ui:composition>
</html>
If I use the EM injected by the @BankDatabase producer field, I am getting following error, when calling the register method twice (!) The first call is successfull.
11:30:20,455 ERROR[javax.enterprise.resource.webcontainer.jsf.application] javax.ejb.EJBException: javax.persistence.TransactionRequiredException: no transaction is in progress: javax.faces.el.EvaluationException: javax.ejb.EJBException: javax.persistence.TransactionRequiredException: no transaction is in progress at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) at javax.faces.component.UICommand.broadcast(UICommand.java:315) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
Using @PersistenceContext private EntityManager database;
always works fine.
Why is that? What is wrong with my code? I googled a lot and always found, that the EntityManager should care for all transactions. I also tried to use the @SessionScope annotation with the producer field, because I thought it might be destroyed to early (producer fields are scoped dependend by default). But nothing changed.
Can you give me a hint?