Why sometimes a reference to an EntityManager inside JPA Entities is needed

In all of my more complex projects, we had to reference  the EntityManager from inside the JPA-Entities. Especially in rich - so entities with business logic, we had to reference the EntityManager somehow. The requirements for referencings the EntityManager were various - and because of NDAs (I'm working mainly as self-employed consultant) hard to share :-) . However I ran into similar issues in a demo application from http://p4j5.dev.java.net as well. The RunAndBike application manages the training unit. BikingUnits  - as well as RunningUnits (both inherit from Unit).

The JPA-Entity Season represents a Training Season (e.g. all units of the year 2008) and is associated with the User. It holds a reference to N abstract Units:

@Entity
@Table(name="TB_SEASON")
public class Season implements Serializable {
   
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long seasonId;

    @Column(name="season_year")
    private int year;

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
    @OrderBy("trainingBegin DESC")
    private List<Unit> trainingUnits;

//lot of code omitted 

}

So you can store BikingUnit:

public class BikingUnit extends Unit {

    private int avgCadence;
    @Enumerated(EnumType.STRING)
    @Column(name="t_type")
    private TrainingType type;
   
    @ManyToOne(cascade=CascadeType.ALL)
    private Bike bike;

//some code omitted
 }

or RunningUnit in it:

@Entity
@NamedQuery(name=RunningUnit.ALL_UNITS,query="Select r From RunningUnit r")
public class RunningUnit extends Unit {
   
    @ManyToOne(cascade=CascadeType.ALL)
    private Shoes shoes;

//some code omitted
 }

 with their specific states and behaviors.

So far, everything works really well. You can manage your units conveniently. Beyond that this solution is extendible, because you could easily introduce just another entity which inherits from the abstract Unit (I got already some request from triathletes for swimming....).

However I just wanted to provide really basic report functionality and compute the average speed. In that particular case it the average speed of Biking and Running Units should be computed separetely (it is not very impressive to have 25km avg speed on a bike, but is noteworthy to be able to run such fast).

To achieve this, I have to filter out all Running/Biking units first in the Season entity: 

    public List<RunningUnit> getRunningUnits() {
        List<RunningUnit> retVal = new ArrayList<RunningUnit>();
        for (Unit unit : getTrainingUnits()) {
            if (unit instanceof RunningUnit)
                retVal.add((RunningUnit) unit);
        }
        Collections.sort(retVal, new UnitComparator());
        return retVal;
    }
It works fine, because you will hardly have more, than 356 units a year - so it is not a huge problem. In case we would have several thousands units - we would run into performance / memory issue with this approach. In that case it would be more appropriate to query the database and not traverse the objects. ...but to access the database, we would need an EntityManager - but it cannot be injected yet. In all of my projects we stored it somehow, mostly in a ThreadLocal.

In real world projects, we needed the access to the EntityManager because of some historization, searches and filtering (mostly because of performance optimization). I always had a bad feeling - because obtaining a reference from an JPA-Entities through a ThreadLocal seemed always a "hack" to me.

Other bloggers ran in the issue as well. In Frank Cornelis wish list, he suggest a query extension:

 

@Entity
@NamedQueries(@NamedQuery(name="byName", query="FROM MyEntity WHERE name = :name"))
public class MyEntity {
@Id
String name;

// ...

public static Query createQueryWhereName(EntityManager em, String name) {
Query query = em.createNamedQuery("byName");
query.setParameter("name", name);
return query;
}
}

The question remains -> how the EntityManager is going to be obtained in his case?

I try to push this issue in my work as EG in JPA 2.0 (JSR-317) -> so if you had similar issues just leave a comment here or write a feedback to the group. You can download the whole application from http://p4j5.dev.java.net (from SVN). The project name is: RunAndBikeApplication (the EAR), and RunAndBikeDB (both Netbeans 6.0 projects, tested on Glassfish v2). The application is available online as well (but slow because of bandwidth).

One solution could be the introduction of a specific LifecycleListener and Lifecycle Call Back methods like:


@PostAttach
public void postAttach(EntityManager manager){

}

@PreDetach
public void preDetach(){}

I will cover the issue of Rich Domain Models and JPA in one of the upcoming issues of the german magazine JavaSPEKTRUM in more detail as well. You can dowload the part 2 for free.

Any thoughts?

Comments:

Hi Adam,

The solution for strong typed queries would be LINQ for Java ;-)
Do you know if there are any advances to have such functionality in Java?

Greetings, Simon

Posted by Simon Martinelli on March 25, 2008 at 12:42 PM CET #

Well, it must be a sort of telepathy (maybe due to the NBDT)? :-) I've just written some code where entities reference the EM, and I was wondering whether it is good or bad.

Indeed my case is different, so I've got still some doubts. Basically I have some entities which represents different properties to be stored in the db. They have many properties in common, with one which is polymorphic, so they are in a hierarchy. One special kind of property is an array, which in turn contains other entities (Composite pattern) as each element of the array must become a record in the database.

When I have to insert a detached entity of course I have to call em.persist(e), but in case of arrays this must be done for all the elements. In the end, I defined a persist() method directly on the entities, which is polymorphic. The EntityManager is retrieved by ThreadLocal.
https://bluemarine.dev.java.net/svn/bluemarine/trunk/src/blueMarine-core/Metadata/MetadataJPAPersistence/src/it/tidalwave/metadata/persistence/jpa/entity

Posted by Fabrizio Giudici on March 25, 2008 at 01:00 PM CET #

Hi Simon,

I experiment with http://qlb.dev.java.net -> if you would like to contribute - just let me know :-),

thanks for your comment,

regards,

adam

Posted by Adam Bien on March 25, 2008 at 09:35 PM CET #

Hi Fabrizio,

perhaps in your case, you could rely on cascading. You could use the merge method instead of persist as well. In that case it will create non-existing and update existing entities.

See you at J1! && blueMarine is great.

It is not telepathy - it is the chip which they injected us :-),

regards,

adam

Posted by Adam Bien on March 26, 2008 at 11:15 AM CET #

Hi. :-) BTW, I missed QLB among your many projects and activities and I'm going to have a look at it, as it could be really useful for me.

Posted by Fabrizio Giudici on March 26, 2008 at 02:25 PM CET #

Hi Adam,

I had a look at QLB and I think it's a good aproach.
Do you know Quaere? http://quaere.codehaus.org/

I wrote an article in my blog comparing Quaere with .NET LINQ:
http://simonmartinelli.blogspot.com/2008/03/quaere-linq.html

In my opinion LINQ is an extremely sexy approach an fully type safe! Unfortunately LINQ requires a lot of changes in the programing language.

I think JPA 2.0 will provide a criteria language, thats also pseudo type safe.

Regards, Simon

Posted by Simon Martinelli on March 26, 2008 at 03:45 PM CET #

Hi Adam,

how would you reference an entitymanager inside a jpa entity these days using JavaEE 6/JPA 2?

Could CDI be used as an alternative to ThreadLocal or is there another standardized way?

Regards, Tom

Posted by Thomas on May 12, 2011 at 11:29 AM CEST #

I'd be keen to hear how JEE 6 and JPA 2 changes the best practices in this regard as well.

Thanks in advance.

Cheers,
Ashley.

Posted by Ashley Aitken on August 23, 2011 at 07:55 PM CEST #

Sorry to say, but your approach does not only feel wrong, it is wrong:

An Entity is an object which is managed. Thus there must be no code inside the managed Entity which tries to manage other entities.

=> the filter method does not belong to the Entity. It must live elsewhere:

public class SeasonManager {
public static List<RunningUnit> getRunningUnits(Season season) {
List<RunningUnit> retVal = new ArrayList<RunningUnit>();
for (Unit unit : season.getTrainingUnits()) {
if (unit instanceof RunningUnit)
retVal.add((RunningUnit) unit);
}
Collections.sort(retVal, new UnitComparator());
return retVal;
}
}

Now it becomes easy to replace the not nice code (get alls, use instanceof) with a named query:

public static List<RunningUnit> getRunningUnits(Season season, EntityManager em) {
return em.createNamedQuery("runningUnits").getResultList();
}

And if the SeasonMgr is a bean, inject the EntityManager:

@Stateless
public class SeasonManager { @PersistenceContext(unitName = "myds")
private EntityManager em;
public List<RunningUnit> getRunningUnits(Season season) {
return em.createNamedQuery("runningUnits").getResultList();
}
}

Now you have a clear approach with obeys the manager -> managed principle.

Just my thoughts but maby not so wrong.

Bebbo

Posted by Bebbo on January 18, 2012 at 01:50 PM CET #

Is is possible to do it now with JEE6, for example using CDI?
thanks

Davide

Posted by Davide on August 01, 2012 at 03:40 PM CEST #

@Davide,

unfortunately, not. It isn't possible to inject the EntityManager into JPA Entities, even with Java EE 6.

I tried to push the topic to JPA Expert Group, but was not very successful.

Write some emails to JPA user list!,

thanks for reading my blog!,

adam

Posted by Adam Bien on August 05, 2012 at 07:40 PM CEST #

I totally agree and support your suggestion.

In fact this would allow to write a Fully Behavioural Model, which is currently not supported in JPA.

Regards,
Carlo.

Posted by Carlo Marchiori on October 24, 2012 at 07:39 PM CEST #

Hey. I have exact these problems. Either I need access to the EntityManger because of performance issues or I have dynamic entities (like those Units ^^) that need to access the database. But I dont want to hack the EntityManager into them, because I also use remoting and then everything will break. Why is there no solution for that? I am evaluating all this J2EE, JPA, CDI, JSF... stuff the last months and all of these technologies are very, very quickly at the end of their limits, when its getting more complex. and than you are within this magic-structure you expected do anything for you and got totally stuck, because everything is so abstracted and far away. by the way: i bought your book, the realworldpatterns, a few minutes ago, and when I won't find solutions for all this stuff I will fall back to php or visual basic 6.0 greets, martin

Posted by hidehawk on December 13, 2012 at 08:30 PM CET #

Hey,

in Hibernate you can execute SQL queries within an Enitity by annotate a property with @Formular

import org.hibernate.annotations.Formula;

@Formula("(select count(*) from t_child c where c.parent_id = parent_id)")
private Integer childcount;

Regards,
Torsten.

Posted by Torsten Knopp on December 04, 2014 at 03:18 PM CET #

Does java ee7 have a solution for this?

For now (7 years since the original post) do we 'just' lookup the entity manager using jndi?

Posted by Mohamed on July 25, 2015 at 06:43 AM CEST #

Is there any way to find an EJB, which is capable of accessing PersistenceContext, in EntityListener?

Posted by Jin Kwon on July 26, 2016 at 07:51 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License