Wouter
Wouter

Reputation: 322

Does using a seperate entitymanagerfactory for each entity cause problems?

I've made a repository class (a class that handles all jpa methods) for each entity type with it's own entitymanagerfactory. Now I've encountered the following error on my many to many relationship:

ValidationException [junit][EclipseLink-7251] Exception Description: The attribute [ID] of class [Person] is mapped to a primary key column in the database. Updates are not allowed.

This error often doesn't occur anymore when debugging and doesn't seem to appear consistently, which leads me to believe it might be a sync issue between managers. (the Pk is handled by jpa - @Id @GeneratedValue - and never changed by me, i do use cascade merge though)

Am I correct in my current assumption that having multiple entitymanagerfactories is a bad idea (and might be related to my problems)?

Upvotes: 0

Views: 139

Answers (2)

Wouter
Wouter

Reputation: 322

I have come to the conclusion that the different EMFs did in fact cause seperate persistence contexts, which caused problems like the validationException.

(I think this happened when 2 different instances of the same entity were managed in 2 different contexts and one of the instances changed it's state though i'm not certain)

Tested like this:

notes:

  • orderweek (= non-owning side) has a one to one bidirectional relationship with week with a cascadeType.ALL.
  • orderRep and weekRep are instances executing CRUD statements related to the Db, each with their own entity manager, created from their own EMF
  • The 2 EMF's are created in seperate factory-classes, but linked to the same DB and should be using the same Persistence Unit 'BreadPU'.
  • I have since realized that multiple EMF's to the same data source is a bad idea

(relevant part of a junit test method)

OrderBill cheapOrder = new OrderBill(5, LocalDate.now());
weekRep.addWeek(cheapOrder.getOrderWeek());
//because of the cascade, both the cheapOrder and the week or now persisted in the DB and managed by weekRep

OrderBill dbOrder = orderRep.updateOrder(cheapOrder);
boolean t2 = weekRep.isManaged(cheapOrder); //true
boolean t3  = orderRep.isManaged(cheapOrder); //false
//It's because this returns false I assume both persistence contexts are different
boolean t4 =  orderRep.isManaged(dbOrder); //true
//If i now use "cheapOrder" to change the order i get the error
//If i now use "dbOrder" to change the order, db gets updated as expected

Upvotes: 0

Sanjeev Dhiman
Sanjeev Dhiman

Reputation: 1199

EntityManagerFactory represents one persistent unit or in other words one data source. If you don't have multiple datasources then you shouldn't create multipe EMF. You can create multiple EntityManagers though (which you can think of like 'connections' to database).

You create EMF like this -

EntityManagerFactory emf = Persistence.createEntityManagerFactory(
  "objectdb://localhost/myDbFile.odb;user=admin;password=admin")

or

 EntityManagerFactory emf =
  Persistence.createEntityManagerFactory("myDbFile.odb");

and you create EntityManager like this -

 EntityManager em = emf.createEntityManager();

From Javadoc - http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManagerFactory.html

Interface used to interact with the entity manager factory for the persistence unit.When the application has finished using the entity manager factory, and/or at application shutdown, the application should close the entity manager factory. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state.

Adding more, you might need Transactions as well which you would create like this -

try {
    em.getTransaction().begin();
    // Operations that modify the database should come here.
    em.getTransaction().commit();
  }
  finally {
    if (em.getTransaction().isActive())
      em.getTransaction().rollback();
  } 

Upvotes: 1

Related Questions