Difference between revisions of "EclipseLink/Examples/JPA/Dynamic"

From Eclipsepedia

Jump to: navigation, search
 
(7 intermediate revisions by 3 users not shown)
Line 208: Line 208:
 
</source>
 
</source>
  
=== API ===
+
=== Dynamic Configuration using API ===
  
 +
Alternatively developers can construct dynamic persistence units using API. A complete example of the same employee demo is available
 +
[http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/branches/2.1/trunk/examples/jpa.employee/eclipselink.example.jpa.employee.dynamic/src/example/EmployeeDynamicMappings.java here].
  
 +
The basic building blocks of constructing dynamic entities using API are:
 +
 +
==== 1. Create the Dynamic Class ====
 +
 +
The dynamic class is an ASM generated subclass of Dynamic entity and it is created with a DynamicClassLoader as:
 +
 +
<source lang="java">
 +
DynamicClassLoader dcl = new DynamicClassLoader(currentLoader);
 +
 +
Class<?> employeeClass = dcl.createDynamicClass(packagePrefix + "Employee");
 +
</source>
 +
 +
==== 2. Create Dynamic Type ====
 +
 +
Using a JPADynamicTypeBuilder  as a factory a new type can be constructed
 +
 +
<source lang="java">
 +
JPADynamicTypeBuilder address = new JPADynamicTypeBuilder(addressClass, null, "D_ADDRESS");
 +
</source>
 +
 +
==== 3. Add the Mappings ====
 +
 +
Finally the mappings are added:
 +
 +
<source lang="java">
 +
address.setPrimaryKeyFields("ADDR_ID");
 +
 +
address.addDirectMapping("id", int.class, "ADDR_ID");
 +
address.addDirectMapping("street", String.class, "STREET");
 +
address.addDirectMapping("city", String.class, "CITY");
 +
address.addDirectMapping("province", String.class, "PROV");
 +
address.addDirectMapping("postalCode", String.class, "P_CODE");
 +
address.addDirectMapping("country", String.class, "COUNTRY");
 +
 +
address.configureSequencing("ADDR_SEQ", "ADDR_ID");
 +
</source>
 +
 +
==== Relationships ====
 +
 +
In addition to these basic steps you will also need to re-use the types when defining relationships between them. To create the Employee to address 1:1 both types are required and used as:
 +
 +
<source lang="java">
 +
OneToOneMapping addressMapping = employee.addOneToOneMapping("address", address.getType(), "ADDR_ID");
 +
addressMapping.setCascadeAll(true);
 +
addressMapping.setIsPrivateOwned(true);
 +
</source>
  
 
== Usage Examples ==
 
== Usage Examples ==
 +
 +
=== Bootstrap ===
 +
 +
In order to bootstrap with dynamic persistence some additional persistence unit properties must be specified.
 +
 +
:''Note: Container managed persistence not supported''
 +
 +
<source lang="java">
 +
Map<String, Object> properties = new HashMap<String, Object>();
 +
 +
properties.put(PersistenceUnitProperties.CLASSLOADER, dcl);
 +
properties.put(PersistenceUnitProperties.WEAVING, "static");
 +
 +
Persistence.createEntityManagerFactory(persistenceUnit, properties);
 +
</source>
 +
 +
=== DynamicEntity API ===
 +
 +
<source lang="java">
 +
DynamicEntity employee = em.createNamedQuery("Employee.findMin", DynamicEntity.class).getSingleResult();
 +
 +
String firstName = employee.<String>get("firstName");
 +
 +
DynamicEntity address = employee.<DynamicEntity>get("address");
 +
 +
Collection<DynamicEntity> phones = employee.<Collection<DynamicEntity>>get("phoneNumbers");
 +
</source>
 +
 +
== Customize Properties Management ==
 +
[[EclipseLink/Examples/JPA/Dynamic/CustomizeAttributes]]
 +
[[Category:EclipseLink/Example/JPA|Dynamic]]

Latest revision as of 19:05, 15 December 2012

Contents

[edit] How to use Dynamic EclipseLink JPA

EclipseLink JPA supports Dynamic Persistence allowing users to map relational tables to virtual classes which are created dynamically at runtime. This support was added in EclipseLink 2.1.0. This example illustrates dynamic persistence using the DynamicEntity interface for all of the persistent types.

[edit] Configuration

With dynamic persistence the mappings and implied entity types can be defined using API within the application code or they can be specified using the eclipselink-orm.xml mapping file.

[edit] eclipselink-orm.xml

There are a couple of key differences versus a standard JPA mapping file:

  • access type of VIRTUAL is used
  • attribute-type must be provided
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
	xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
	<package>example.jpa.dynamic.model.employee</package>
 
	<object-type-converter name="gender-converter"
		object-type="String" data-type="String">
		<conversion-value object-value="Male" data-value="M" />
		<conversion-value object-value="Female" data-value="F" />
	</object-type-converter>
 
	<named-query name="Employee.findAll">
		<query>SELECT e FROM Employee e ORDER BY e.lastName, e.firstName</query>
		<hint name="eclipselink.query-results-cache" value="True" />
	</named-query>
 
	<named-query name="Employee.findMin">
		<query>SELECT e FROM Employee e WHERE e.id IN (SELECT MIN(ee.id) FROM
			Employee ee)</query>
	</named-query>
 
	<entity class="Address" access="VIRTUAL">
		<attributes>
			<id name="id" attribute-type="Integer">
				<column name="ADDRESS_ID" />
				<generated-value strategy="SEQUENCE" generator="address-generator" />
				<sequence-generator name="address-generator"
					sequence-name="ADDR_SEQ" />
			</id>
			<basic name="city" attribute-type="String" />
			<basic name="country" attribute-type="String" />
			<basic name="province" attribute-type="String" />
			<basic name="postalCode" attribute-type="String">
				<column name="P_CODE" />
			</basic>
			<basic name="street" attribute-type="String" />
		</attributes>
	</entity>
 
	<entity class="PhoneNumber" access="VIRTUAL">
		<table name="PHONE" />
		<attributes>
			<id name="id" attribute-type="Integer">
				<column name="PHONE_NUM_ID" />
				<generated-value strategy="SEQUENCE" />
			</id>
			<basic name="type" attribute-type="String">
				<column updatable="false" />
			</basic>
			<basic name="areaCode" attribute-type="String">
				<column name="AREA_CODE" />
			</basic>
			<basic name="number" attribute-type="String">
				<column name="P_NUMBER" />
			</basic>
			<many-to-one name="owner" fetch="EAGER" target-entity="Employee">
				<join-column name="EMP_ID" />
			</many-to-one>
		</attributes>
	</entity>
 
	<entity class="Employee" access="VIRTUAL">
		<secondary-table name="SALARY" />
		<attributes>
			<id name="id" attribute-type="Integer">
				<column name="EMP_ID" />
				<generated-value strategy="SEQUENCE" generator="employee-generator" />
				<sequence-generator name="employee-generator"
					sequence-name="EMP_SEQ" />
			</id>
			<basic name="firstName" attribute-type="String">
				<column name="F_NAME" />
			</basic>
			<basic name="lastName" attribute-type="String">
				<column name="L_NAME" />
			</basic>
			<basic name="startTime" attribute-type="String">
				<column name="START_TIME" />
			</basic>
			<basic name="endTime" attribute-type="String">
				<column name="END_TIME" />
			</basic>
			<basic name="gender" attribute-type="String">
				<column name="GENDER" />
				<convert>gender-converter</convert>
			</basic>
			<basic name="salary" attribute-type="Integer">
				<column table="SALARY" />
			</basic>
 
			<version name="version" attribute-type="Long" />
 
			<many-to-one name="manager" fetch="EAGER" optional="true"
				target-entity="Employee">
				<join-column name="MANAGER_ID" />
			</many-to-one>
 
			<one-to-many name="managedEmployees" mapped-by="manager"
				target-entity="Employee" attribute-type="java.util.List" />
 
			<one-to-many name="phoneNumbers" mapped-by="owner"
				target-entity="PhoneNumber" attribute-type="java.util.List">
				<cascade>
					<cascade-all />
				</cascade>
				<private-owned />
			</one-to-many>
 
			<one-to-one name="address" fetch="EAGER" target-entity="Address">
				<join-column name="ADDR_ID" />
				<cascade>
					<cascade-all />
				</cascade>
				<private-owned />
			</one-to-one>
 
			<many-to-many name="projects" target-entity="Project"
				attribute-type="java.util.List">
				<join-table name="PROJ_EMP">
					<join-column name="EMP_ID" />
					<inverse-join-column name="PROJ_ID" />
				</join-table>
			</many-to-many>
 
			<element-collection name="responsibilities"
				attribute-type="java.util.List" target-class="String">
				<column name="RESPON_DESC" />
				<collection-table name="RESPONS" />
			</element-collection>
 
			<embedded name="period" attribute-type="EmploymentPeriod" />
 
		</attributes>
	</entity>
 
	<entity class="Project" access="VIRTUAL">
		<inheritance strategy="JOINED" />
		<discriminator-column name="PROJ_TYPE"
			discriminator-type="CHAR" />
		<attributes>
			<id name="id" attribute-type="Integer">
				<column name="PROJ_ID" />
				<generated-value strategy="SEQUENCE" generator="project-generator" />
				<sequence-generator name="project-generator"
					sequence-name="PROJ_SEQ" />
			</id>
			<basic name="description" attribute-type="String">
				<column name="DESCRIP" />
			</basic>
			<basic name="name" attribute-type="String">
				<column name="PROJ_NAME" />
			</basic>
			<version name="version" attribute-type="Long" />
			<many-to-one name="teamLeader" fetch="EAGER"
				target-entity="Employee">
				<join-column name="LEADER_ID" />
			</many-to-one>
		</attributes>
	</entity>
 
	<entity class="SmallProject" parent-class="Project" access="VIRTUAL">
		<table name="PROJECT" />
		<discriminator-value>S</discriminator-value>
	</entity>
 
	<entity class="LargeProject" parent-class="Project" access="VIRTUAL">
		<table name="LPROJECT" />
		<discriminator-value>L</discriminator-value>
		<attributes>
			<basic name="budget" attribute-type="Double" />
			<basic name="milestone" attribute-type="java.util.Calendar">
				<temporal>TIMESTAMP</temporal>
			</basic>
		</attributes>
	</entity>
 
	<embeddable class="EmploymentPeriod" access="VIRTUAL">
		<attributes>
			<basic name="startDate" attribute-type="java.util.Date">
				<column name="START_DATE" />
				<temporal>DATE</temporal>
			</basic>
			<basic name="endDate" attribute-type="java.util.Date">
				<column name="END_DATE" />
				<temporal>DATE</temporal>
			</basic>
		</attributes>
	</embeddable>
 
</entity-mappings>

[edit] Dynamic Configuration using API

Alternatively developers can construct dynamic persistence units using API. A complete example of the same employee demo is available here.

The basic building blocks of constructing dynamic entities using API are:

[edit] 1. Create the Dynamic Class

The dynamic class is an ASM generated subclass of Dynamic entity and it is created with a DynamicClassLoader as:

DynamicClassLoader dcl = new DynamicClassLoader(currentLoader);
 
Class<?> employeeClass = dcl.createDynamicClass(packagePrefix + "Employee");

[edit] 2. Create Dynamic Type

Using a JPADynamicTypeBuilder as a factory a new type can be constructed

JPADynamicTypeBuilder address = new JPADynamicTypeBuilder(addressClass, null, "D_ADDRESS");

[edit] 3. Add the Mappings

Finally the mappings are added:

address.setPrimaryKeyFields("ADDR_ID");
 
address.addDirectMapping("id", int.class, "ADDR_ID");
address.addDirectMapping("street", String.class, "STREET");
address.addDirectMapping("city", String.class, "CITY");
address.addDirectMapping("province", String.class, "PROV");
address.addDirectMapping("postalCode", String.class, "P_CODE");
address.addDirectMapping("country", String.class, "COUNTRY");
 
address.configureSequencing("ADDR_SEQ", "ADDR_ID");

[edit] Relationships

In addition to these basic steps you will also need to re-use the types when defining relationships between them. To create the Employee to address 1:1 both types are required and used as:

OneToOneMapping addressMapping = employee.addOneToOneMapping("address", address.getType(), "ADDR_ID");
addressMapping.setCascadeAll(true);
addressMapping.setIsPrivateOwned(true);

[edit] Usage Examples

[edit] Bootstrap

In order to bootstrap with dynamic persistence some additional persistence unit properties must be specified.

Note: Container managed persistence not supported
Map<String, Object> properties = new HashMap<String, Object>();
 
properties.put(PersistenceUnitProperties.CLASSLOADER, dcl);
properties.put(PersistenceUnitProperties.WEAVING, "static");
 
Persistence.createEntityManagerFactory(persistenceUnit, properties);

[edit] DynamicEntity API

DynamicEntity employee = em.createNamedQuery("Employee.findMin", DynamicEntity.class).getSingleResult();
 
String firstName = employee.<String>get("firstName"); 
 
DynamicEntity address = employee.<DynamicEntity>get("address"); 
 
Collection<DynamicEntity> phones = employee.<Collection<DynamicEntity>>get("phoneNumbers");

[edit] Customize Properties Management

EclipseLink/Examples/JPA/Dynamic/CustomizeAttributes