Jump to: navigation, search

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

Line 1: Line 1:
 
= How to use Dynamic EclipseLink JPA =
 
= 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  
+
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/Release/2.1.0|EclipseLink 2.1.0]]. This example illustrates dynamic persistence using the [http://www.eclipse.org/eclipselink/api/2.1/org/eclipse/persistence/dynamic/DynamicEntity.html DynamicEntity] interface for all of the persistent types.
  
This how-to illustrates how EclipseLink can be extended to deliver all of its JPA functionality in a dynamic scenario where no Java class exists for the entity and optionally where no XML is provided. This allows the EclipseLink JPA solution to be used in more dynamic environments where either the mode is unknown at development time or the application is simply dynamic in nature.
+
== 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.
  
== Example ==
+
=== eclipselink-orm.xml ===
  
The dynamic entity extension is currently illustrated through test cases in the example.
+
There are a couple of key differences versus a standard JPA mapping file:
 +
* access type of '''VIRTUAL''' is used
 +
* attribute-type must be provided
  
 +
<source lang="xml">
 +
<?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">
  
=== Creating an Entity on the Fly ===
+
<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>
 +
</source>
 +
 
 +
=== API ===
 +
 
 +
 
 +
 
 +
== Usage Examples ==

Revision as of 11:09, 14 June 2010

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.

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.

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>

API

Usage Examples