Использование внедренного EntityManager в иерархиях классов - PullRequest
3 голосов
/ 20 марта 2010

Работает следующий код:

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


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

Но следующая иерархия дает исключение TransactionRequiredException в Glassfish 3.0 (и стандартных аннотациях JPA с EclipseLink.) В строке 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 и родственные методы в подклассы, но я бы хотелдержите их все вместе в одном месте.

Я не пробовал, но это может быть потому, что мой базовый класс абстрактный, но я бы хотел изучить подходящий метод для такого (ИМХО распространенного) варианта использования,

Ответы [ 3 ]

1 голос
/ 20 марта 2010

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

Обновление: Я был неправ, согласно разделу 5.2.3 спецификации платформы Java EE 5, внедрение разрешено в полях и методах суперкласса.

Я пошел немного дальше и провел небольшой тест со своей стороны, используя аналогичный код 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 для простых операций доступа к данным. Посмотрите на этот предыдущий ответ .

0 голосов
/ 21 марта 2010

Проблема заключалась не в использовании менеджера сущностей с внедрением суперкласса, а в вызове другого метода 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 не был компонентом, а checkAuthority был статическим методом с использованием (не JTA) EntityManagerFactory. Затем я изменил OtherBean, чтобы расширить MySuperBean тоже. Я думаю, что в этом случае, когда OtherBean заканчивается checkAuthority, JTA завершает транзакцию и MySuperBean insert не может найти транзакцию для сохранения сущности. Понятно, что EJB без состояния не позволяют другим EJB продолжать транзакцию.

Как Паскаль, я изначально думал, что внедрение не работает с наследованием, но эта проблема продолжалась, когда я напрямую вызывал em.persist() в подклассе. После этого я наконец смог проверить другие возможные причины.

Спасибо за все комментарии.

0 голосов
/ 20 марта 2010

Ваш подход не ошибочен (если он работает)

Однако более распространено либо использовать (вводить) Dao и вызывать методы для него, либо если Dao является избыточным слоем, который только переноситEntityManager, вы можете просто вызывать методы на EntityManager напрямую.Конечно, подвергая EntityManager подклассам через защищенный метод получения.

getEntityManager().persist(e);
...