问题
This is my first post after many research on this problem.
This example is running under Jboss 7.1 with seam 3.1 (solder + persistence + faces) with seam managed persistence context
I'm facing a problem, the classical failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
when using a converter on Entity beans. The aim is to stay 100% Object oriented, by reusing the JPA model.
in beans.xml, org.jboss.seam.transaction.TransactionInterceptor
is activated
Entity beans :
@Entity
public class Member implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
@Column(name = "phone_number")
private String phoneNumber;
@ManyToMany
private List<Statut> listeStatut = new ArrayList<Statut>();
// getters, setters, hashcode, equals
}
@Entity
public class Statut implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy="listeStatut")
private List<Member> members = new ArrayList<Member>();
// getters, setters, hashcode, equals
}
The JSF page :
<h:form>
<h:selectManyCheckbox id="stat" value="#{memberModif.member.listeStatut}">
<f:converter converterId="statutConverter"/>
<f:selectItems value="#{memberModif.statutsPossibles}" var="statut" itemValue="#{statut}" itemLabel="#{statut.name}" />
</h:selectManyCheckbox>
<h:commandLink id="register" action="#{memberModif.modifier()}" value="Modifier">
<f:param name="cid" value="#{javax.enterprise.context.conversation.id}"/>
</h:commandLink>
</h:form>
The backing bean (I tried with ConversationScoped after SessionScoped --> same problem)
@ConversationScoped
@Named
public class MemberModif implements Serializable {
private static final long serialVersionUID = -291355942822086126L;
@Inject
private Logger log;
@Inject
private EntityManager em;
@Inject Conversation conversation;
private Member member;
@SuppressWarnings("unused")
@PostConstruct
private void init() {
if (conversation.isTransient()) {
conversation.begin();
}
}
public String modifier() {
em.merge(member);
}
public Member getMember() {
if (member == null) {
member = em.createQuery("from Member m where m.id=:id",Member.class).setParameter("id", new Long(0)).getSingleResult();
}
return member;
}
public List<Statut> getStatutsPossibles() {
return em.createQuery("from Statut", Statut.class).getResultList();
}
}
And the converter (strongly inspired by seam ObjectConverter
) :
@FacesConverter("statutConverter")
public class StatutConverter implements Converter, Serializable {
final private Map<String, Statut> converterMap = new HashMap<String, Statut>();
final private Map<Statut, String> reverseConverterMap = new HashMap<Statut, String>();
@Inject
private transient Conversation conversation;
private final transient Logger log = Logger.getLogger(StatutConverter.class);
private int incrementor = 1;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (this.conversation.isTransient()) {
log.warn("Conversion attempted without a long running conversation");
}
return this.converterMap.get(value);
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (this.conversation.isTransient()) {
log.warn("Conversion attempted without a long running conversation");
}
if (this.reverseConverterMap.containsKey(value)) {
return this.reverseConverterMap.get(value);
} else {
final String incrementorStringValue = String.valueOf(this.incrementor++);
this.converterMap.put(incrementorStringValue, (Statut)value);
this.reverseConverterMap.put( (Statut)value, incrementorStringValue);
return incrementorStringValue;
}
}
}
Please note that I put this converter here to avoid you searching over the net for the seam implementation, but it is the same as using <s:objectConverter/>
tag instead of <f:converter converterId="statutConverter"/>
Any help would be greetly appreciated.
回答1:
You should access the objects in the same transaction. If you are sure you are doing that already, you could try getting the entitymanager by looking it up in the context instead of injecting it. Ive had a simular problem which was resolved that way. You can also initialize the collection in the transaction when you first got your reference to it.
Hibernate.initialize(yourCollection);
回答2:
Take a look at this: selectManyCheckbox LazyInitializationException on process validation
Try:
<f:attribute name="collectionType" value="java.util.ArrayList" />;
on your <h:selectManyCheckbox>
来源:https://stackoverflow.com/questions/9886390/lazy-loading-exception-when-using-jsf-converter-refering-to-a-collection