Persistence operations with SDO DataObjects

OpenJPA SDO extension works exactly as any other JPA application, exxcept that the persistence unit is activated to process SDO Types and JPA interfaces accept and return DataObjects as result of persistent operations such as persist(), merge() or query.

Configuring for SDO Persistence

OpenJPA SDO extension is activated by configuring persistence configuration file META-INF/persistence.xml. The persistence configuration file is configured adding following properties under <properties> tag as follows:

        <property name="openjpa.EntityManagerFactory" value="sdo"/>
        <property name="openjpa.MetaDataFactory"      value="sdo(Resources=META-INF/person.xsd;META-INF/po.xsd;)"/>

The openjpa.EntityManagerFactory property tells OpenJPA runtime to use a EntityManager Factory specialized to handle SDO DataObjects.

The openjpa.MetaDataFactory property tells OpenJPA runtime where to look for persistent classes. Normally, the persistent classes are listed in <class> or <jar> tag. For SDO, specify one of more *.xsd files. The file names are resolved against the current classpath.

Storing DataObjects

DataObjects are stored exactly as normal POJOs using JPA. * Create a DataObject via helper instances in SDO API such as DataFactory.

	DataObject createPerson(String ssn, String first, String last, int age) {
		Type type = getType("Person");
		DataObject data = DataFactory.INSTANCE.create(type);
		data.set("ssn", ssn);
		data.setString("firstName", first);
		data.setString("lastName", last);
		data.setInt("age", age);
		return data;
	}
  • Invoke EntityManager.persist() on an active transaction.
		DataObject data = createPerson(ssn, "John", "Doe", 42);
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		em.persist(data);
		em.getTransaction().commit();

The result of persist operation is transitive. It not only stores the DataObject passed as argument but all other DataObjects reachable from it.

Querying DataObjects

DataObjects are queried using powerful JPA Query language JPQL (Java Persistence Query Language}. The results of query is returned as a List of DataObjects as shown in the example:

		EntityManager em = emf.createEntityManager();
		String jpql = "SELECT o FROM PurchaseOrderType o WHERE o.shipTo.name=:name";
		Query query = em.createQuery(jpql);
		query.setParameter("name", "Alice Smith");
		List<DataObject> result = query.getResultList();

Updating DataObjects

DataObjects are updated via EntityManager.merge(). The entire closure of given DataObject is updated if modified and a merged DataObject is returned to the caller as shown in the example:

		OpenJPAEntityManager em = emf.createEntityManager();
		String jpql = "SELECT o FROM PurchaseOrderType o WHERE o.shipTo.name=:name";
		Query query = em.createQuery(jpql);
		query.setParameter("name", "Alice Smith");
		List<DataObject> result = query.getResultList();
		assertFalse(result.isEmpty());
		for (DataObject dataObject : result) {
			int before = count("USAddress");
			dataObject.getDataObject("billTo").setString("name", "John Doe");
			em.getTransaction().begin();
			DataObject merged = em.merge(dataObject);
			em.getTransaction().commit();
			String changedName = merged.getDataObject("billTo").getString("name");
			assertEquals("John Doe", changedName);
			int after = count("USAddress");
			assertEquals(before, after);
		}

Finding DataObject by id

Finding a DataObject by identity departs slightly from EntityManager.find() behavior. The signature of EntityManager.find() as defined by JPA specification is

  public <T> T find(Class<T> cls, Object id);

To use find() with SDO, the user must pass

  • DataObject.class as the first argument
  • The id must be a String that is prefixed with the SDO Type name. For example, to find a Person DataObject with an integer id 1234, the caller must supply the id argument to find() method as a String "Person:1234".
		String id = "Person:"+ssn;
		DataObject result = em.find(DataObject.class, id);

This departure from normal JPA find method arises because SDO DataObject represents a relaxed-type system as opposed to a strong-type Java system for which JPA is originally targeted.

Normal Java behaviour would be calling

  Person person = em.find(Person.class, 1234);

But SDO extension to OpenJPA supports a client programming model where there is no Person class to begin with. Also find() to return DataObject, must accept DataObject.class because of its method signature. Hence, the type of DataObject being looked up can not be passed via the first argument (as it is possible when a concrete Person.class could be supplied). Hence, the convention of prefixing the identifier with the Type name.

Deleting DataObjects

DataObjects are deleted via EntityManager.remove() method.