Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "EclipseLink/UserGuide/JPA/Advanced JPA Development/Composite Persistence Units"
m |
m |
||
Line 41: | Line 41: | ||
==Configuring Composite Persistence and Composite Member Persistence Units == | ==Configuring Composite Persistence and Composite Member Persistence Units == | ||
− | + | Composite persistence units and their member persistence units are configured in the same way as regular persistence units, and with some additional properties specific to composite and composite member persistence units. | |
− | + | ||
Certain properties must be defined on the composite persistence unit; certain properties must be defined on composite member persistence units; and other properties may be defined on either. | Certain properties must be defined on the composite persistence unit; certain properties must be defined on composite member persistence units; and other properties may be defined on either. | ||
Line 95: | Line 94: | ||
'''Note:''' If <tt>eclipselink.composite-unit.member</tt> is passed to the <tt>createEntityManagerFactory</tt> method or if it is set in system properties, it is ignored. | '''Note:''' If <tt>eclipselink.composite-unit.member</tt> is passed to the <tt>createEntityManagerFactory</tt> method or if it is set in system properties, it is ignored. | ||
− | + | <!---//REVIEWERS: Design doc also says "If this property is set to true, the EntityManagerFactory can still be created, but it cannot be connected." I don't understand, as true is perfectly valid, no?// //ANDREI: true is perfectly valid. That means persistence unit can only be used as a member of composite - cannot be used as an independent persistence unit. Motivation: persistence unit that has dependency on classes in other persistence unit(s) - impossible to use standalone, still possible to use as a member of composite, of course the persistence unit(s) on which it depends should also be members in the same composite. Logically I would prefer to fail when the factory is created - but that would be a problem with application servers, so the next best solution is to fail on attempt to actually use the factory - createEntityManager// --> | |
− | + | ||
=== Passing EntityManagerFactory Properties to Composite Member Persistent Units === | === Passing EntityManagerFactory Properties to Composite Member Persistent Units === | ||
+ | As with regular persistence unit you can override properties specified in <tt>persistence.xml</tt> with new ones passed to the <tt>createEntityManagerFactory</tt> method. Therefore, you can change some properties at runtime, for example connection parameters. Do do this with composite member persistence units, use the <tt>eclipselink.composite-unit.properties</tt> property. The value is a <tt>Map</tt> that is keyed on composite member persistence unit names; the value is a <tt>Map</tt> that contains all properties to be passed to this member persistence unit. For example, | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
<source lang="java"> | <source lang="java"> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Map props1 = new HashMap(); | Map props1 = new HashMap(); | ||
Revision as of 09:15, 7 July 2011
EclipseLink JPA
EclipseLink | |
Website | |
Download | |
Community | |
Mailing List • Forums • IRC • mattermost | |
Issues | |
Open • Help Wanted • Bug Day | |
Contribute | |
Browse Source |
Key API
Examples
This page is being reviewed.
Composite Persistence Units
Multiple persistence units with unique sets of entity types can be exposed as a single persistence context by using a composite persistence unit. A persistent unit that is part of a composite persistent unit is called a composite member persistent unit.
With composite persistence units:
- Mapping relationships can be established among any of the entities in the composite.
- The persistence context can access entities stored in different data sources.
- Queries and transactions can be performed transparently across the complete set of entities.
For example, you could persist data from a single context into different data sources, as shown below:
em.persist(new A(..)); em.persist(new Z(..)); // Insert A into database1; insert Z into database2: // the two databases can be from different vendors. em.flush();
Configuring Composite Persistence and Composite Member Persistence Units
Composite persistence units and their member persistence units are configured in the same way as regular persistence units, and with some additional properties specific to composite and composite member persistence units.
Certain properties must be defined on the composite persistence unit; certain properties must be defined on composite member persistence units; and other properties may be defined on either.
- The transaction type must be specified in the composite persistence unit. Transaction types of composite members are ignored.
- Data sources must be specified in composite member persistence units. Those specified in the composite are ignored.
- The eclipselink.composite-unit property must be set on the composite persistent unit.
- The eclipselink.composite-unit.member property can only be set on composite member persitent units.
The Persistence Unit Properties table and the Entity Manager Properties tables, below, show how those and other properties are processed, depending on whether they are set on the composite or on the member persistent unit.
Configuring Composite Persistent Units in persistence.xml
A minimal configuration of a composite persistent unit in persistence.xml requires the following:
- Use the eclipselink.composite-unit property to specify that it is a composite persistence unit. (Note: If this property is passed to the createEntityManagerFactory method or if it is set in system properties, it is ignored.)
- Use the <jar-file> element to specify the jar files containing the composite member persistent units. The composite persistence unit will contain all the persistence units found in the jar files specified.
For example,
... <jar-file>member1.jar</jar-file> <jar-file>member2.jar</jar-file> <properties> <property name="eclipselink.composite-unit" value="true"/> </properties> ...
Configuring Composite Member Persistent Units in persistence.xml
Use the eclipselink.composite-unit.member property to specify whether or not a persistent unit should be a member of a composite persistence unit:
- true specifies that the persistent unit must be a member of a composite persistence unit.
- false specifies that the persistent unit cannot be a member of a composite persistence unit (if, for example, it has dependencies on other persistence unit(s)).
For example,
... <properties> <property name="eclipselink.composite-unit.member" value="true"/> </properties> ...
The eclipselink.composite-unit.member property is not required and defaults to false if not specified. //REVIEWERS: <-- Is that statement true?// //ANDREI: Yes. "true" required only in case the persistence unit cannot be used independently (not as a composite member)//
Note: If eclipselink.composite-unit.member is passed to the createEntityManagerFactory method or if it is set in system properties, it is ignored.
Passing EntityManagerFactory Properties to Composite Member Persistent Units
As with regular persistence unit you can override properties specified in persistence.xml with new ones passed to the createEntityManagerFactory method. Therefore, you can change some properties at runtime, for example connection parameters. Do do this with composite member persistence units, use the eclipselink.composite-unit.properties property. The value is a Map that is keyed on composite member persistence unit names; the value is a Map that contains all properties to be passed to this member persistence unit. For example,
Map props1 = new HashMap(); props1.put(PersistenceUnitProperties.JDBC_USER, "user1"); props1.put(PersistenceUnitProperties.JDBC_PASSWORD, "password1"); props1.put(PersistenceUnitProperties.JDBC_DRIVER, "oracle.jdbc.OracleDriver"); props1.put(PersistenceUnitProperties.JDBC_URL, "jdbc:oracle:thin:@oracle_db_url:1521:db"); Map props2 = new HashMap(); props2.put(PersistenceUnitProperties.JDBC_USER, "user2"); props2.put(PersistenceUnitProperties.JDBC_PASSWORD, "password2"); props2.put(PersistenceUnitProperties.JDBC_DRIVER, "oracle.mysql.OracleDriver"); props2.put(PersistenceUnitProperties.JDBC_URL, " jdbc:mysql:@oracle_sql_url:3306/user2"); Map memberProps = new HashMap(); memberProps.put("memberPu1", props1); memberProps.put("memberPu2", props2); Map props = new HashMap(); props.put("eclipselink.composite-unit.properties", memberProps); EntityManagerFactory emf = Persistence.createEntityManagerFactory("composite", props);
Examples
In the following example, the composite persistence unit compositePU specifies the transaction type and the server platform. It will contain all persistence units defined in member1.jar and member2.jar files.
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> <persistence-unit name="compositePu" transaction-type="JTA"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <jar-file>member1.jar</jar-file> <jar-file>member2.jar</jar-file> <properties> <property name="eclipselink.composite-unit" value="true"/> <property name="eclipselink.target-server" value="WebLogic_10"/> </properties> </persistence-unit> </persistence>
In the following example, the composite member persistence unit memberPu1 is defined in the member1.jar file. It can be used independently as well as inside composite persistence unit.
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> <persistence-unit name="memberPu1" transaction-type="JTA"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <mapping-file>META-INF/advanced-entity-mappings1.xml</mapping-file> <jta-data-source>jdbc/OracleJtaDS</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="eclipselink.target-server" value="WebLogic_10"/> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform"/> </properties> </persistence-unit> </persistence>
In the following example, the composite member persistence unit memberPu2 is defined in the member2.jar file. It has dependency on a class defined in member1.jar and cannotbe used independently.
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> <persistence-unit name="memberPu2"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <mapping-file>META-INF/advanced-entity-mappings2.xml</mapping-file> <jta-data-source>jdbc/MySqlJtaDS</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="eclipselink.composite-unit.member" value="true"/> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.MySQLPlatform"/> </properties> </persistence-unit> </persistence>
Deploying and Accessing a Composite Persistence Unit
All three jars – the composite and the two members– should be deployed on the same class loader. If they are deployed to an application server, the jars should be packed in an ear file. If they run standalone, the jars should be added to the class path.
A composite persistence unit can be accessed as with any other persistence unit.
- It can be accessed using injection, for example:
@PersistenceUnit(unitName="compositePu") EntityManagerFactory entityManagerFactory; @PersistenceUnit(unitName="compositePu") EntityManager entityManager;
- Or it can be created manually, using [Persistence.createEntityManagerFactory ], as shown in the following example:
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("compositePu", properties);
Persistence Unit Properties
Persistence unit properties can be set on the EntityManagerFactory as follow:
- Composite persistence unit properties can be specified either in the composite persistence unit's persistence.xml file or passed to the its createEntityManagerFactory() method.
- Composite member persistence unit properties can either be specified in the composite member persistence unit's persistence.xml file or passed to the composite persistence unit's createEntityManagerFactory() method through the eclipselink.composite.properties property.
//REVIEWERS: Can't the properties also be passed to createEntityManager()? If so, why would you do that instead of using createEntityManagerFactory()?// //ANDREI: Not all properties that could be passed to createEMF could be passed to createEM. Also properties passed to createEMF applied to all EMs created by the factory.</tt>?//
The following table shows how properties set on a composite persistence unit and its members are handled when properties are set on both. //REVIEWERS: Is that correct?//
//ANDREI: "when properties are set on both" sounds a bit confusing, but correct//
For complete PersistenceUnitProperties> reference documentation, see [|PersistenceUnitProperties].
PersistenceUnitProperties. | property name | composite pu | composite member pu | comment |
COMPOSITE_UNIT | eclipselink.composite-unit | Processed | Advanced | If specified by member then the member is substituted for its own members. //REVIEWERS: I think this means "If specified by a composite member persistence unit ..." But what does the rest of the sentence mean?
//ANDREI: If member itself is a composite then it's substituted by its members
|
COMPOSITE_UNIT_MEMBER | eclipselink.composite-unit.member | Advanced | Processed | if specified by composite persistence unit, the composite must be member of another composite persistence unit. //REVIEWERS: This suggests that composite PUs can be composite member PUs of other composite PUs. Is that correct? Any limitations?//
//ANDREI: Yes. All pus involved should have unique names// |
COMPOSITE_PROPERTIES | eclipselink.composite.properties | Processed | Ignored | |
TRANSACTION_TYPE | javax.persistence.transactionType | Processed | Ignored | |
TARGET_SERVER | eclipselink.target-server | Processed | Ignored | |
LOGGING_* | eclipselink.logging.* | Processed | Ignored | |
PROFILER | eclipselink.profiler | Processed | Ignored | |
COORDINATION_* | eclipselink.cache.coordination.* | Processed | Ignored | |
SESSION_NAME | eclipselink.session-name | Processed | Advanced | The member session name is used to read the session from sessions.xml, but the deployed session always has the same name as the member persistence unit (as it is defined in memberPuInfo.getPersistenceUnitName()) |
DEPLOY_ON_STARTUP | eclipselink.deploy-on-startup | Processed | Ignored | |
VALIDATION_ONLY_PROPERTY | eclipselink.validation-only | Processed | processed | //REVIEWERS: bug 348815: WRONG BEHAVIOUR, should be processed by composite only, ignored by member persistence unit. Workaround for now: specify the property in the composite and in all its members.//
//ANDREI: It's a known bug in 2.3. The users should know this and should have a workaround// |
VALIDATION_* | eclipselink.validation.* | Processed | Ignored | |
CLASSLOADER | eclipselink.classloader | Processed | Ignored | |
THROW_EXCEPTIONS | eclipselink.orm.throw.exceptions | Processed | Ignored | |
FLUSH_CLEAR_CACHE | eclipselink.flush-clear.cache | Processed | Ignored | |
VALIDATE_EXISTENCE | eclipselink.validate-existence | Processed | Ignored | |
JOIN_EXISTING_TRANSACTION | eclipselink.transaction.join-existing | Processed | Ignored | |
PERSISTENCE_CONTEXT_* | eclipselink.persistence-context.* | Processed | Ignored | |
ALLOW_ZERO_ID | eclipselink.allow-zero-id | Processed | Ignored | |
SESSION_CUSTOMIZER | eclipselink.session.customizer | Processed | Processed | Customizers of member persistence units are processed before the composite persistence unit's customizer. |
SESSIONS_XML | eclipselink.sessions-xml | Exception | Processed | Composite persitence units cannot be read from sessions.xml. Note that a non-composite persistence unit should be able to use a SessionBroker defined in sessions.xml. |
JTA_DATASOURCE | javax.persistence.jtaDataSource | Ignored | Processed | |
NON_JTA_DATASOURCE | javax.persistence.nonJtaDataSource | Ignored | Processed | |
NATIVE_SQL | eclipselink.jdbc.native-sql | Ignored | Processed | |
SQL_CAST | eclipselink.jdbc.sql-cast | Ignored | Processed | |
JDBC_* | javax.persistence.jdbc.* eclipselink.jdbc.* | Ignored | Processed | |
CONNECTION_POOL_* | Ignored | Processed | ||
PARTITIONING.* | eclipselink.partitioning.* | Ignored | Processed | |
EXCLUSIVE_CONNECTION_* | eclipselink.jdbc.exclusive-connection.* | Ignored | Processed | |
CACHE.* | eclipselink.cache.* | Ignored | Processed | |
TARGET_DATABASE | eclipselink.target-database | Ignored | Processed | |
TABLE_CREATION_SUFFIX | eclipselink.ddl-generation.table-creation-suffix | Ignored | Processed | |
EXCLUDE_ECLIPSELINK_ORM_FILE | eclipselink.exclude-eclipselink-orm | Ignored | Processed | |
WEAVING | eclipselink.weaving | Processed | Ignored | A composite persistent unit switches weaving on and off for all its member persistent units. |
WEAVING_* | eclipselink.weaving.* | Ignored | Processed | If the weaving is on, members use their own weaving properties. |
DESCRIPTOR_CUSTOMIZER_* | eclipselink.descriptor.customizer.* | Ignored | Processed | //REVIEWERS: what about this from design doc: "TODO? Should we follow the same pattern as SessionCustomizer and process composite's DescriptorCustomizers after members' ones?"//
//ANDREI: Skip it - it's has not been implemented// |
NATIVE_QUERY_UPPERCASE_COLUMNS | eclipselink.jdbc.uppercase-columns | Ignored | Processed | |
UPPERCASE_COLUMN_NAMES | eclipselink.jpa.uppercase-column-names | Ignored | Processed | |
BATCH_WRITING.* | eclipselink.jdbc.batch-writing.* | Ignored | Processed | |
SESSION_EVENT_LISTENER_CLASS | eclipselink.session-event-listener | Processed | Processed | EventListener defined by a composite member won't receive evens risen by a UnitOfWork - only events risen by it's member. Also see bug 348766. EventListener specified by composite will receive all event (risen by either unit of work or members). |
Exception_HANDLER_CLASS | eclipselink.exception-handler | Processed | Processed | First ExceptionHandler specified by member handles exception. If it is not specified or fails then composite's ExceptionHandler handles the original exception. |
INCLUDE_DESCRIPTOR_QUERIES | eclipselink.session.include.descriptor.queries | Ignored | Processed | |
ID_VALIDATION | eclipselink.id-validation | Ignored | Processed | |
TEMPORAL_MUTABLE | eclipselink.temporal.mutable | Ignored | Processed | |
ORM_SCHEMA_VALIDATION | eclipselink.orm.validate.schema | Ignored | Processed | |
DDL_* | Ignored | Processed | ||
PESSIMISTIC_LOCK_TIMEOUT | javax.persistence.lock.timeout | Ignored | Processed | |
QUERY_TIMEOUT | javax.persistence.query.timeout | Ignored | Processed | |
ORACLE_PROXY_TYPE | eclipselink.oracle.proxy-type | Ignored | Processed |
Entity Manager Properties
Persistence unit properties can be set on the EntityManager as follow:
- Composite entity manager properties can be passed directly to the createEntityManager() method or to the setProperty method.
- Composite member properties can be passed to the same methods through the eclipselink.composite.properties property.
EntityManagerProperties. | property name | composite pu | composite member pu | comment |
COMPOSITE_PROPERTIES | eclipselink.composite.properties | Processed | Ignored | |
FLUSH_CLEAR_CACHE | eclipselink.flush-clear.cache | Processed | Ignored | |
VALIDATE_EXISTENCE | eclipselink.validate-existence | Processed | Ignored | |
JOIN_EXISTING_TRANSACTION | eclipselink.transaction.join-existing | Processed | Ignored | |
PERSISTENCE_CONTEXT_* | eclipselink.persistence-context.* | Processed | Ignored | |
ORDER_UPDATES | eclipselink.order-updates | Processed | Ignored | |
EXCLUSIVE_CONNECTION_* | eclipselink.jdbc.exclusive-connection.* | Ignored | Processed | |
JDBC_DRIVER | javax.persistence.jdbc.driver | Ignored | Processed | |
JDBC_URL | javax.persistence.jdbc.url | Ignored | Processed | |
JDBC_USER | javax.persistence.jdbc.user | Ignored | Processed | |
JDBC_PASSWORD | javax.persistence.jdbc.password | Ignored | Processed | |
JTA_DATASOURCE | javax.persistence.jtaDataSource | Ignored | Processed | |
NON_JTA_DATASOURCE | javax.persistence.nonJtaDataSource | Ignored | Processed | |
CONNECTION_POLICY | eclipselink.jdbc.connection-policy | Ignored | Processed | |
ORACLE_PROXY_TYPE | eclipselink.oracle.proxy-type | Ignored | Processed |
Limitations
Joins across tables in different data sources are not supported. This limitation affects mapping, query execution, and optimizations. For example:
- Entities mapped in different composite members cannot be joined in a query.
- If deleting an entity causes deletion from a table that is mapped by another composite member, then a "delete all" query cannot be performed. Therefore a delete all cannot be used if an entity:
- has ElementCollection mapped in another composite member,
- owns bidirectional relationship with a JoinTable with the target mapped in another composite member,
- has any reference mapping that is privately owned with the target mapped in another composite member.
The inheritance hierarchy cannot be shared between different composite members.
If the target of a reference mapping is defined in a different composite member and JoinTable is used, the join table must belong to the target composite member. Such mappings must be unidirectional: the "invert" mapping cannot use mappedBy. That is because JoinTable must be defined in the same composite member with the target entity. Master mapping requires it to be in slave's member, slave mapping - in master's.You can work around this limitation by defining independent invert mapping with its own JoinTable. If you maintain both sides of the relationship, the two join tables will be in sync.
A native query created without a result class must specify the target composite member persistence unit, for example:
em.createNativeQuery("SELECT F_NAME FROM MBR2_EMPLOYEE").setHint(QueryHints.COMPOSITE_UNIT_MEMBER, "composite-advanced-member_2").getResultList();
Extensions
You can specify ElementCollection with primitive type target values with CollectionTable defined in a different composite member persistence unit, using annotations or eclipselink-orm.xml as described below:
- Annotations
@ElementCollection() @CollectionTable(name = "MBR1_RESPONS", joinColumns=@JoinColumn(name="EMP_ID")) @CompositeMember("composite-advanced-member_1") @Column(name = "DESCRIPTION") public Collection<String> getResponsibilities() { return responsibilities; }
- eclipselink-orm.xml
<element-collection name="responsibilities" composite-member="xml-composite-advanced-member_3"> <column name="DESCRIPTION"/> <collection-table name="XML_MBR3_RESPONS"> <join-column name="EMP_ID"/> </collection-table> </element-collection>
No @CompositeMember annotation (or composite-member attribute) is required if CollectionTable is defined in the same composite member persistence unit as the source.