I'm reading Pro JPA 2. It has the following figure:
Per the figure, many entity managers can point to the same persistence context. I'm trying to accomplish this in Java SE:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");
EntityManager em = emf.createEntityManager();
EntityManager em2 = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = new Employee(1);
employee.setName("Bob");
employee.setSalary(100000);
em.persist(employee);
System.out.println("em" + em.find(Employee.class, 1));
System.out.println("em all Employees " + em.createQuery("SELECT e from Employee e", Employee.class).getResultList());
System.out.println("em2 Employee" + em2.find(Employee.class, 1));
System.out.println("em2 all Employees " + em2.createQuery("SELECT e from Employee e", Employee.class).getResultList());
em.getTransaction().commit();
em.close();
em2.close();
emf.close();
The output is:
em Employee(id=1, name=Bob, salary=100000.0)
em all Employees[Employee(id=1, name=Bob, salary=100000.0)]
em2 Employee null
em2 all Employees[]
So, it appears that em and em2 are pointing to different persistence contexts. Is there a way to have different entity managers manage the same persistence context in Java SE?
Related
A JPA transaction commit is supposed to save all changes to the entities associated with the persistence context that have happened so far. So it matters a lot where the commit() is located. How much does it matter where the begin() is? Consider the following two scenarios, both of which create entity x, associate x with a persistence context, and later modify that entity and [purport to] save the changes to x to the database:
// Scenario A
EntityManager em = ...
MyEntity x = new MyEntity();
em.getTransaction().begin();
em.persist(x);
em.getTransaction().commit();
// ... do some stuff ...
x.a = val1;
x.setB(val2);
em.getTransaction().begin(); // *a "late begin"*
em.getTransaction().commit();
vs.
// Scenario B
EntityManager em = ...
MyEntity x = new MyEntity();
em.getTransaction().begin();
em.persist(x);
em.getTransaction().commit();
// ... do some stuff ...
em.getTransaction().begin(); // *an "early begin"*
x.a = val1;
x.setB(val2);
em.getTransaction().commit();
In both scenarios, object x belongs to the persistence context of EntityManager em.
Isn't it the case that, in both scenarios, the second commit will save all changes to em's context, including those to x.a and x.b, that have happened since the first commit?
In this case, what is the functional difference between the two scenarios?
Let's assume we use no Spring, Java Beans, and other advanced technologies; just the Java Persistence API and the OpenJPA implementation.
I have the following code which I call from the front end
public Login update(Login i) {
em = emf.createEntityManager();
em.getTransaction().begin();
Login result=infoDAO.update(i);
em.getTransaction().commit();
em.close();
return result;
}
public Login update(Login i) {
return em.merge(i);
}
I have
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("HRTool-JPA");
protected EntityManager em=emf.createEntityManager();
The methods are being called and the values are passed to the DB correctly(I am using Apache derby) but I can see the new changed values in the DB only after I disconnect and reconnect to it. Am I missing some step after merge ? I am new to JPA and appreciate any suggestions on the same
By default Hibernate keep the requests in its cache and Hibernate decides when it wants to execute them.
You can try to add a em.flush() after em.merge()
It will execute all the requests left in its cache.
I can create history of an entity with a HistoryCustomizer
#Entity
#Customizer(MyHistoryCustomizer.class)
public class Employee {..}
the HistoryCustomizer is something like this one:
public class MyHistoryCustomizer implements DescriptorCustomizer {
public void customize(ClassDescriptor descriptor) {
HistoryPolicy policy = new HistoryPolicy();
policy.addHistoryTableName("EMPLOYEE_HIST");
policy.addStartFieldName("START_DATE");
policy.addEndFieldName("END_DATE");
descriptor.setHistoryPolicy(policy);
}
}
The history objects can be fetched with the "AS_OF" hint
javax.persistence.Query historyQuery = em
.createQuery("SELECT e FROM Employee e", Employee.class)
.setParameter("id", id)
.setHint(QueryHints.AS_OF, "yyyy/MM/dd HH:mm:ss.SSS")
.setHint(QueryHints.READ_ONLY, HintValues.TRUE)
.setHint(QueryHints.MAINTAIN_CACHE, HintValues.FALSE);
just fine BUT, if you start accessing objects referenced by this historical object, the referenced objects will be the actual version of them. So the Employee from last year (fetched by a historical query) will have the current Address assigned to it and no the one it used to have last year.
How can I tell EclipseLink (2.5.0) to fetch the related object from the past as well?
In order to query the historical state of several - not just one like above - entities, we have to create an EclipseLink specific HistoricalSession. Queries run through this session will use the same historical timestamp and represent the proper historical state of the object graph.
I am using JPA in other parts of the code, so I will start with converting the JPA Query to an EclipseLink ReadAllQuery.
The HistoricalSession has its own entity cache, so that the historical entities do not mix with the normal ones.
// Get the EclipseLink ServerSession from the JPA EntitiyManagerFactory
Server serverSession = JpaHelper.getServerSession(emf);
// Only a ClientSession can give us a HistoricalSession so ask one from the ServerSession
ClientSession session = serverSession.acquireClientSession();
// Create the HistoricalSessions. A HistoricalSession is sticked to a point in the past and all the queries are executed at that time.
Session historicalSessionAfterFirstChild = session.acquireHistoricalSession(new AsOfClause(afterFirstChildAdded));
ReadAllQuery q;
Query jpaQuery = em.createQuery(query);
jpaQuery.setParameter("root", "parent");
// Extract the EclipseLink ReadAllQuery from the JPA Query. We can use named queries this way.
q=JpaHelper.getReadAllQuery(jpaQuery);
// This is a possible EclipseLink bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=441193
List<Object> arguments = new Vector<Object>();
arguments.add("parent");
q.setArgumentValues(arguments);
Vector<Parent> historyAwareParents ;
// Execute the query
historyAwareParents = (Vector<Parent>) historicalSessionAfterFirstChild.executeQuery(q);
for (Child c : historyAwareParents.get(0).children) {
System.out.println(c.getExtension() + " " + c.getRoot());
}
How to persist an Array List of type Entity in JPA ?
For example, there is an entity called "Table".
I am creating an array list ArrayList<Table> table = new ArrayList<Table>();
Trying to persist it using entityManager.persist(table); and it did not work. Any solution for this ?
EntityManagerFactory emf = Persistence.createEntityManagerFactory("TDEMSPU");
em = emf.createEntityManager();
em.getTransaction().begin();
List<Enquiry> tempEnqList = tempEnqList();
for (Iterator<Enquiry> it = tempEnqList.iterator(); it.hasNext();) {
Enquiry enquiry = it.next();
em.persist(enquiry);
em.flush();
em.clear();
}
em.getTransaction().commit();
Just iterate over it and persist it one by one
Since Java 8 you can use forEach with a method reference:
List<SomeEntity> entities = ...;
entities.forEach(entityManager::persist);
I'm setting up a basic test data util and want to keep track of all the data that the EntityManager handles. Rather than just having a bunch of lists for each entity is there a way to grab everything being managed by the EntityManager in one fell swoop?
So instead of this:
EntityManager em;
List<Entity1> a;
List<Entity2> b;
...
List<Entityn> n;
cleanup() {
for(Entity1 e : a) em.remove(e);
for(Entity2 f : b) em.remove(f);
...
for(Entityn z : n) em.remove(z);
}
I want something like this;
EntityManager em;
cleanup() {
List<Object> allEntities = em.getAllManagedEntities(); //<-this doesnt exist
for(Object o : allEntities) em.remove(o);
}
Not sure if this is possible, but I just would image that the manager knows what it is managing? Or, if you have any ideas of managing a bunch of entities easily.
I think this might help:
for (EntityType<?> entity : entityManager.getMetamodel().getEntities()) {
final String className = entity.getName();
log.debug("Trying select * from: " + className);
Query q = entityManager.createQuery("from " + className + " c");
q.getResultList().iterator();
log.debug("ok: " + className);
}
Basically EntityManager::MetaModel contains the MetaData information regarding the Entities managed.
What JPA provider are you using?
There is nothing in the JPA API for this.
If using EclipseLink, you can use,
em.unwrap(UnitOfWorkImpl.class).getCloneMapping().keySet()
If you need to remove all entities inserted during a test, you can execute the test inside a transaction and then rollback that transaction. See 9.3.5.4 Transaction management
as an example of this approach.