开发者

Using injected EntityManager in class hierarchies

开发者 https://www.devze.com 2022-12-23 20:00 出处:网络
The following code works: @Stateless @LocalBean public class MyClass { @PersistenceContext(name = \"MyPU\")

The following code works:

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


       public void myBusinessMethod(MyEntity e)
   开发者_如何学Go    {
          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.


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.


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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消