The ObjectDB manual (https://www.objectdb.com/java/jpa/query/jpql/from) gives an example of using JOIN FETCH to avoid excessive round trips to the database:
SELECT c FROM Country c JOIN FETCH c.capital
I've tried a few variants of the following example, and haven't been able to get this to work. See the code below: I'm looking for a single line to be printed out (for the single person in the database), with 2 addresses. Instead, I get two lines printed (the same person, printed twice), with the address shown as null in each case. If I don't close the entity manager, then I get the correct addresses (obviously fetched lazily), but still 2 results. What should I be doing to get what I want out of this query?
Note that I need to get the fetch mode specified in the query, not in the entity annotations, since I'm looking at ObjectDB as a possible replacement for an existing system where lots of queries run over the same set of objects, returning different sets of data. The same relationship will need to be retrieved both eagerly and lazily in different queries.
package testing; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.MapKeyTemporal; import javax.persistence.OneToMany; import javax.persistence.Persistence; import javax.persistence.TemporalType; import javax.persistence.TypedQuery; public class Eager2 { public static void main(String[] args) throws Exception { File file = new File("eager.odb"); if (file.exists()) { file.delete(); } file.createNewFile(); EntityManagerFactory emf = Persistence.createEntityManagerFactory("eager.odb"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Person p = new Person(); p.setName("Peter Smith"); Address address1 = new Address("123 Acacia Avenue"); p.addAddress(new SimpleDateFormat("yyyyMMdd").parse("20000101"),address1); em.persist(address1); Address address2 = new Address("654 Olive Road"); p.addAddress(new SimpleDateFormat("yyyyMMdd").parse("20100101"),address2); em.persist(address2); em.persist(p); em.getTransaction().commit(); TypedQuery<Address> aq = em.createQuery("select a from Address a",Address.class); System.out.println(aq.getResultList()); // Prints out both addresses OK. TypedQuery<Person> q = em.createQuery( "select p from Person p join fetch p.addressHistory",Person.class); List<Person> results = q.getResultList(); em.close(); emf.close(); for (Person person : results) // Executes loop body twice. { System.out.println("PERSON:" + person); // Address is shown as null. } } @Entity public static class Person { @Id @GeneratedValue private long id; private String name; @OneToMany @MapKeyTemporal(TemporalType.DATE) private Map<Date,Address> addressHistory = new HashMap<Date,Address>(); public long getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Map<Date,Address> getAddressHistory() { return addressHistory; } public void addAddress(Date start,Address address) { addressHistory.put(start,address); } public String toString() { return name + ":" + addressHistory; } } @Entity public static class Address { @Id @GeneratedValue private long id; private String address; public long getId() { return id; } public Address(String address) { this.address = address; } public String getAddress() { return address; } public String toString() { return address; } } }