以下代码有效:
@Stateless
@LocalBean
public class MyClass
{
@PersistenceContext(name = "MyPU")
EntityManager em;
public void myBusinessMethod(MyEntity e)
{
em.persist(e);
}
}
但是以下层次结构在persist
行中的Glassfish 3.0(以及带有EclipseLink的标准JPA注释)中给出了TransactionRequiredException。
@Stateless
@LocalBean
public class MyClass extends MyBaseClass
{
public void myBusinessMethod(MyEntity e)
{
super.update(e);
}
}
public abstract class MyBaseClass
{
@PersistenceContext(name = "MyPU")
EntityManager em;
public void update(Object e)
{
em.persist(e);
}
}
对于我的EJB,我在抽象类中收集了通用代码以获得更清晰的代码。 (update
还可以保存执行操作的人员,以及我的所有实体何时实现接口。)
这个问题不是致命的,我可以简单地将update
和姐妹方法复制到子类中,但我想将它们全部保存在一个地方。
我没有尝试,但这可能是因为我的基类是抽象的,但我想学习这种(恕我直言)常见用例的正确方法。
答案 0 :(得分:1)
AFAIK,你不能注入超类,所以你必须注入实际EJB的字段或方法。你可以这样做:
public class MyBaseEJB {
public abstract EntityManager getEM();
public void update(Object e) {
getEM().persist(e);
}
}
@Stateless
public class MyEJB extends MyBaseEJB {
@PersistenceContext
EntityManager em;
public EntityManager getEM() { return em;}
}
击> <击> 撞击>
更新:我错了,根据Java EE 5平台规范的5.2.3节,在超类字段和方法中允许注入。
我进一步使用类似的代码GlassFish v3和EclipseLink对我进行了一次小测试,我无法重现你的问题。所以我怀疑你persistence.xml
有些问题。你能提供吗?你使用的是transaction-type="JTA"
吗?以防万一,这是我使用的那个:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd" version="2.0">
<persistence-unit name="MyPU" transaction-type="JTA">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/q2484443</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
顺便说一下,我认为跳过简单数据访问操作的DAO模式是完全没错的。看看this previous answer。
答案 1 :(得分:0)
你的方法没有错(如果有效)
然而,更常见的是使用(注入)Dao并在其上调用方法,或者如果Dao是仅包装EntityManager
的冗余层,则可以简单地调用{{1上的方法直接。当然,通过受保护的getter将EntityManager
暴露给子类。
EntityManager
答案 2 :(得分:0)
问题不是使用超类'注入的实体管理器,而是调用另一个EJB的方法:例如
@Stateless
@LocalBean
public class MyBean extends MySuperBean
{
@EJB
com.example.project.MyOtherBean otherBean;
public boolean myService(String userName, MyEntity entity)
{
if(otherBean.checkAuthority(userName))
{
super.insert(entity);
}
}
}
当OtherBean
不是bean而checkAuthority
是使用(非JTA)EntityManagerFactory
的静态方法时,我正在使用此模式。然后我更改了OtherBean
以扩展MySuperBean
。我认为,在这种情况下,当OtherBean
结束checkAuthority
时,JTA会结束交易,而MySuperBean
的{{1}}找不到要保留实体的交易。可以理解的是,无状态EJB不会让其他EJB继续进行交易。
作为Pascal,我最初认为注入不适用于继承,但是当我在子类中直接调用insert
时,这个问题仍然存在。在此之后,我终于能够检查其他可能的原因。
感谢所有输入。