Home » Eclipse Projects » EclipseLink » EclipseLink and Dynamic Entities
EclipseLink and Dynamic Entities [message #514151] |
Fri, 12 February 2010 16:02 |
Klaus G ønbæk Messages: 3 Registered: January 2010 |
Junior Member |
|
|
Hi All
I have spent a couple of weeks working with dynamic entities , either created on the fly from custom models, or created from existing tables, and I would like to share some of my findings.
Here is an example which tries to find an existing dynamic entity, if it doesn't exist, it will be created, and then it will be updated.
package com.example
import org.eclipse.persistence.descriptors.*;
import org.eclipse.persistence.descriptors.changetracking.*;
import org.eclipse.persistence.dynamic.*;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.jpa.*;
import org.eclipse.persistence.jpa.dynamic.*;
import org.eclipse.persistence.sessions.*;
import java.util.*;
import javax.persistence.*;
/**
* Simple Example that creates a dynamic type, and uses it with find(), and persist()
* @author Klaus Groenbaek
*/
public class DynamicEntityExample {
public static void main(String[] args) {
EntityManagerFactory emf = getEMF();
EntityManager em = emf.createEntityManager();
try {
// you need a session to get the dynamic classloader
Session session = JpaHelper.getEntityManager(em).getServerSession();
DynamicClassLoader dcl = DynamicClassLoader.lookup(session);
// The name of the database table, and the JavaClass backing your dynamic entity
String tableName = "MyTable";
String objectName = tableName;
// create the dynamic class
Class<?> clazz = dcl.createDynamicClass("com.example." + objectName);
DynamicTypeBuilder builder = null;
// DynamicTypeBuilder, causes em.Find() to throw NPE
//builder = new DynamicTypeBuilder(clazz, null, tableName);
// JPADynamicTypeBuilder, if you use this builder entities wont update after they are changed
//builder = new JPADynamicTypeBuilder(clazz, null, tableName);
// Use a CustomTypeBuilder to fix these shortcummings
builder = new CustomDynamicTypeBuilder(clazz, null, tableName);
// set mapping for two properties
builder.addDirectMapping("MyID", Long.class, "ID");
builder.addDirectMapping("MyString", String.class, "STRING");
builder.setPrimaryKeyFields("ID");
// get an register the type
DynamicType type = builder.getType();
DynamicHelper dynamicHelper = new JPADynamicHelper(em);
dynamicHelper.addTypes(true /* create table */, false /*foreign key constraints*/, type);
// try to find the entity with ID 42. Will fail if you used DynamicTypeBuilder.
Long pk = 42L;
DynamicEntity entiry = (DynamicEntity) em.find(type.getJavaClass(), pk);
if (entiry == null) {
// now create a new entity and save it
entiry = type.newDynamicEntity();
entiry.set("MyID", pk);
entiry.set("MyString", "Hello World");
em.getTransaction().begin();
em.persist(entiry);
em.getTransaction().commit();
}
// now change a property and store the object again this generates an UPDATE (If you used the CustomDynamicTypeBuilder)
entiry.set("MyString", "Godbye World");
em.getTransaction().begin();
em.persist(entiry);
em.getTransaction().commit();
}
catch (DynamicException e) {
e.printStackTrace();
}
finally {
em.close();
}
}
/**
* Creates the EntityManagerFactory, connecting to a MySQL DB
* @return Returns an entityManagerFactory
*/
private static EntityManagerFactory getEMF() {
HashMap<String, String> connectionProperties;
connectionProperties = new HashMap<String, String>();
connectionProperties.put("eclipselink.jdbc.password", "pass");
connectionProperties.put("eclipselink.jdbc.user", "user");
connectionProperties.put("eclipselink.jdbc.driver", "com.mysql.jdbc.Driver");
connectionProperties.put("eclipselink.jdbc.url", "jdbc:mysql://localhost/db");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ObjectDatabase", connectionProperties);
return emf;
}
/**
* The default DymanicTypeBuilder has two problems 1. It doesn't define a CMPPolicy (which result in a NPE when
* using em.find() [EntityManagerImpl.findInternal(), 2.0.0.jar line 644], The JPADynamicTypeBuilder addresses this
* issue <br>
* 2. The default ObjectChangePolicy on Dynamic Entities is AttributeChangeTrackingPolicy, however this causes
* the entities to not update when persist os called on a modified object
*/
static class CustomDynamicTypeBuilder extends DynamicTypeBuilder {
public CustomDynamicTypeBuilder(Class<?> dynamicClass, DynamicType parentType, String... tableNames) {
super(dynamicClass, parentType, tableNames);
}
@Override
protected void configure(ClassDescriptor descriptor, String... tableNames) {
super.configure(descriptor, tableNames);
if (descriptor.getCMPPolicy() == null) {
descriptor.setCMPPolicy(new DynamicIdentityPolicy());
}
// override the default policy, which is AttributeChangeTrackingPolicy
descriptor.setObjectChangePolicy(new DeferredChangeDetectionPolicy());
}
}
}
The documentation on building dynamic types using EclipseLink 2.0.0 is outdated, so I'm not sure I have done everything they way you're supposed to - Comments are welcome.
I'm hoping this example will save others the vast amounts of time I have spent digging around in the EclipseLink source code. Especially that entities created using JPADynamicTypeBuilder won't update when they are re-persisted.
Other observations:
Dynamic Entities doesn't work with JPA 2.0 CriteriaQuery
Thanks to the EclipseLink team for a great library, that saves a lot of time when you have to support 8 different databses.
[Updated on: Fri, 12 February 2010 16:03] Report message to a moderator
|
|
| | | | |
Goto Forum:
Current Time: Thu Sep 19 13:43:40 GMT 2024
Powered by FUDForum. Page generated in 0.05592 seconds
|