在类层次结构中使用注入的 EntityManager

发布于 2024-08-26 07:18:02 字数 979 浏览 14 评论 0原文

以下代码有效:

@Stateless
@LocalBean
public class MyClass 
{
       @PersistenceContext(name = "MyPU")
       EntityManager em;


       public void myBusinessMethod(MyEntity e)
       {
          em.persist(e);
       }
 }

但以下层次结构在 Glassfish 3.0(以及带有 EclipseLink 的标准 JPA 注释)中的 persist 行处给出了 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 和姊妹方法复制到子类中,但是我想将它们全部放在一个地方。

我没有尝试,但这可能是因为我的基类是抽象的,但我想为这种(恕我直言,常见)用例学习正确的方法。

The following code works:

@Stateless
@LocalBean
public class MyClass 
{
       @PersistenceContext(name = "MyPU")
       EntityManager em;


       public void myBusinessMethod(MyEntity e)
       {
          em.persist(e);
       }
 }

But the following hierarchy gives a TransactionRequiredException in Glassfish 3.0 (and standard JPA annotations with EclipseLink.) at the line of persist.

 @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);
       }
 }   

For my EJB's I collected common code in an abstract class for cleaner code. (update also saves who did the operation and when, all my entities implement an interface.)

This problem is not fatal, I can simply copy update and sister methods to subclasses but I would like to keep all of them together in a single place.

I didn't try but this may be because my base class is abstract, but I would like to learn a proper method for such a (IMHO common) use case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千柳 2024-09-02 07:18:02

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 模式来进行简单的数据访问操作是完全可以的。看看之前的答案

AFAIK, you can't inject into a super class, so you have to inject into a field or method of the actual EJB. You could do something like this:

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;}
} 

Update: I was wrong, according to the section 5.2.3 of the Java EE 5 platform specification, injection is allowed in super class fields and methods.

I went a bit further and did a small test on my side using similar code, GlassFish v3 and EclipseLink and I can't reproduce your problem. So I suspect some kind of problem with your persistence.xml. Could you provide it? Are you using a transaction-type="JTA"? Just in case, here is the one I used:

<?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>

BTW, I think that it's perfectly fine to skip the DAO pattern for simple data access operations. Have a look at this previous answer.

春风十里 2024-09-02 07:18:02

您的方法没有错误(如果有效)

,但是更常见的是使用(注入)Dao 并在其上调用方法,或者如果 Dao 是仅包装 EntityManager 的冗余层,您可以直接调用 EntityManager 上的方法。当然,通过受保护的 getter 将 EntityManager 暴露给子类。

getEntityManager().persist(e);

Your approach isn't wrong (if it works)

However it is more common to either use (inject) a Dao and call methods on it, or if the Dao is a redundant layer that only wraps the EntityManager, you can simply call the methods on EntityManager directly. Of course, exposing the EntityManager to subclasses via a protected getter.

getEntityManager().persist(e);
南城旧梦 2024-09-02 07:18:02

问题不在于使用超类的注入实体管理器,而是调用另一个 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结束事务,MySuperBeaninsert可以找不到事务来持久化实体。可以理解的是,无状态 EJB 不允许其他 EJB 继续进行事务。

作为 Pascal,我最初认为注入不适用于继承,但是当我在子类中直接调用 em.persist() 时,这个问题仍然存在。之后我终于能够检查其他可能的原因。

感谢您的所有意见。

The problem was not using superclass' injected entity manager, but calling another EJB's method: e.g.

@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);
     }
   }
 }

I was using this pattern when OtherBean was not a bean and checkAuthority was a static method using (non-JTA) EntityManagerFactory. Then I changed OtherBean to extend MySuperBean too. I think, in this case, when OtherBean ends checkAuthority, JTA ends the transaction and MySuperBean's insert can't find a transaction to persist entity. Understandably Stateless EJB's don't let fellow EJB's to proceed the transaction.

As Pascal, I initially thought that injection does not work with inheritance but this problem continued when I directly called em.persist() in the subclass. After this I finally was able to check other possible causes.

Thanks for all the input.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文