3

次のコードが機能します。

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


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

しかし、次の階層では、Glassfish 3.0 (および EclipseLink を使用した標準 JPA アノテーション) の . 行で TransactionRequiredException が発生し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);
       }
 }   

私の EJB では、共通コードを抽象クラスに集めて、よりクリーンなコードにしました。(update誰がいつ操作を行ったか、すべてのエンティティがインターフェイスを実装していることも保存します。)

この問題は致命的ではありません。単純にupdateメソッドをサブクラスにコピーして姉妹化することはできますが、それらすべてを 1 つの場所にまとめておきたいと考えています。

私は試しませんでしたが、これは私の基本クラスが抽象的であるためかもしれませんが、そのような(私見一般的な)ユースケースの適切な方法を学びたいと思います。

4

3 に答える 3

1

私の知る限り、スーパークラスに注入することはできないため、実際の 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 パターンをスキップしてもまったく問題ないと思います。この前の回答を見てください。

于 2010-03-20T19:40:28.417 に答える
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);
     }
   }
 }

OtherBeanBeanではなく、checkAuthority(非JTA)を使用する静的メソッドであるときに、このパターンを使用していましたEntityManagerFactory。それから私もOtherBean延長するように変更しMySuperBeanました。OtherBeanこの場合、終了するcheckAuthorityと、JTAはトランザクションを終了し、エンティティを永続化するトランザクションを見つけることができないMySuperBeanと思います。insert当然のことながら、ステートレスEJBは、他のEJBにトランザクションを続行させません。

Pascalとして、最初はインジェクションは継承では機能しないと思っていem.persist()ましたが、サブクラスを直接呼び出したときにこの問題が続きました。この後、私はついに他の考えられる原因を確認することができました。

すべての入力をありがとう。

于 2010-03-20T22:43:23.430 に答える
0

あなたのアプローチは間違っていません(うまくいく場合)

ただし、Dao を使用 (注入) してその上でメソッドを呼び出すことがより一般的です。または、Dao が をラップするだけの冗長レイヤーである場合は、単純に直接EntityManagerメソッドを呼び出すことができます。EntityManagerもちろん、EntityManager保護されたゲッターを介してサブクラスに公開します。

getEntityManager().persist(e);
于 2010-03-20T19:41:13.253 に答える