Eclipselink实体映射缓存

时间:2014-01-16 22:14:08

标签: jpa orm mapping eclipselink entitymanager

我正在为我的项目使用EclipseLink。 我扩展XMLMetadataSource(以提供自定义类加载器),因为我持久化的实体是运行时创建的。它运作正常。

当我关注时,我会收到“未知实体类型”。

  • 创建实体

  • 创建映射

  • 创建实体管理器工厂,提供自定义类加载器

  • 创建实体经理并坚持。 - 它工作正常。

  • 现在删除实体,并从类加载器中删除

  • 创建相同的实体,

  • 再次创建映射(当然它看起来一样)

  • 尝试使用新属性刷新实体管理器工厂(新的类加载器,映射文件)

  • 尝试坚持 - 抱怨“未知类型”

任何想法,如果EL缓存XML映射。 我试图再次重新创建工厂,但同样的错误。

我尝试了MySQL和Derby。使用'drop-and-create-tables'和'create-or-extend-tables'。

同样的结果。

3 个答案:

答案 0 :(得分:2)

我用eclipse链接提交了一个错误。

https://bugs.eclipse.org/bugs/show_bug.cgi?id=426310

答案 1 :(得分:1)

它不是EL中每个人说的错误。但是问题在于EL“没有构建或重新创建'类 - > class_descriptor'地图(一个内部地图,它包含每个实体的Class对象和实体描述)。我偶然发现了这一点。对于那些感兴趣的人,这里有一个示例代码可能会有所帮助。

public class Test1 {
public Test1(String pu, Map<String, Object> props ) {
    pu_name = pu;        
    properties = new HashMap<String, Object> ();
    properties.putAll(props);
    loader = new MyClassLoader();
}
public void initialization( ) {                
    mms = new WAMetadataSource();
    properties.put(PersistenceUnitProperties.METADATA_SOURCE, mms);
    properties.put(PersistenceUnitProperties.CLASSLOADER,loader);

    if(emf == null || !emf.isOpen()) {
        synchronized(Test1.class) {
            if (emf == null || !emf.isOpen()) {
                emf = Persistence.createEntityManagerFactory(pu_name, properties);                    
            } 
        }            
    } else {
                JpaHelper.getEntityManagerFactory(emf).refreshMetadata(properties);        
    }
    System.out.println("======> refreshed. emf.hascode : " + emf.hashCode() + ", loader.h : " + loader.hashCode());
}    public EntityManager getEntityManager(Map<String, Object> props) {
    if (em == null) {
        em = emf.createEntityManager(props);
    }

    return em;
} public void persist(Object obj) {
    try {
        getEntityManager(properties);
        System.out.println("===> em.hascode =" + em.hashCode() +", " +  JpaHelper.getEntityManager(em).getProperties().get(PersistenceUnitProperties.CLASSLOADER).hashCode() );
        em.clear();
        em.getTransaction().begin();
        em.persist(obj);
        em.getTransaction().commit();
    } finally {
    }    
}public Object getRuntimeEntityObject(int ii) {
        Object obj=null;
        Class clazz = loader.loadClass("com.xxx.sample.entity.runtime.User");
        if(ii == 1){
            obj = clazz.getConstructor(String.class).newInstance("Jai Ramjiki-1");                
        } else {
            obj = clazz.getConstructor(String.class).newInstance("Jai Ramjiki-2");
        }
        obj = clazz.cast(obj);
        return obj;
}public static void main(String[] args) {
    Map<String, Object> props = new HashMap<String, Object>();
    props.put(PersistenceUnitProperties.JDBC_DRIVER, "com.mysql.jdbc.Driver");
    props.put(PersistenceUnitProperties.JDBC_URL, "jdbc:mysql://localhost:3306/test" );
    props.put(PersistenceUnitProperties.JDBC_USER, "root");
    props.put(PersistenceUnitProperties.JDBC_PASSWORD, "root");
    props.put(PersistenceUnitProperties.DDL_GENERATION, "create-or-extend-tables");

    Test1 t1 = new Test1("mysql", props);         
    Object obj1 = t1.getRuntimeEntityObject(1);     
    System.out.println(" ****> obj1 = " + obj1 + ", classloader hashcode : " + obj1.getClass().getClassLoader().hashCode() );
    t1.initialization();
    t1.persist(obj1);
    System.out.println("Class 1 : " + obj1.getClass().hashCode() + ", obj1 : " + obj1);
    t1.close();

    // now drop the previous class loader and rerun same. 

    Test1 t2 = new Test1("mysql", props);
    Object obj2 = t2.getRuntimeEntityObject(2);
    System.out.println(" ****> obj2 = " + obj2 + ", classloader hashcode : " + obj2.getClass().getClassLoader().hashCode() );
    t2.initialization();
    t2.persist(obj2);
    t2.close();


    Object obj3 = t1.getRuntimeEntityObject(1);
    System.out.println(" ****> obj3 = " + obj3 + ", classloader hashcode : " + obj3.getClass().getClassLoader().hashCode() );
    t1.persist(obj3);


}

AND扩展XMLMetadatSource

 @Override
public XMLEntityMappings getEntityMappings(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) {
    properties.put(PersistenceUnitProperties.METADATA_SOURCE_XML_FILE, "eclipselink-orm-user.xml");
    properties.put(PersistenceUnitProperties.VALIDATOR_FACTORY, null);
    return super.getEntityMappings(properties, classLoader, log);
}

在CustomClassloader中使用javassist创建一个运行时类,它扩展了ClassLoader

    public void createRuntimeClass(String className) throws Exception {        
    CtClass bclass = pool.makeClass(className);
    bclass.addConstructor(CtNewConstructor.defaultConstructor(bclass));        
    Map<String, String> fields = new HashMap<String, String>(); 
    addFields(fields); 
    int noOfFields = fields.size(); 
    CtClass[] fclasses = new CtClass[noOfFields];

    int ii=0;
    for (Entry<String, String> field : fields.entrySet()) {
        String fieldName = field.getKey();
        String fieldType = field.getValue();
        //.. code to add field
        bclass.addField(bfield);            
        //add getter method.
        // add getter and setters
    }        
    CtConstructor userConstructor = CtNewConstructor.make(constructorSource, bclass);
    bclass.addConstructor(userConstructor);
    byte bytes [] = bclass.toBytecode();        
    Class cls = bclass.toClass(this, null);
    loadedClasses.put(className, cls);
    loadClassBytes.put(className, bytes);    
}

并覆盖loadClass和getResourceAsStream方法。

public Class<?> loadClass(String name) throws ClassNotFoundException {return clazz = loadedClasses.get(name);}

public InputStream getResourceAsStream(String name) {return loadClassBytes.get(className);}

希望这会有所帮助

EL提供了一种清除当前项目缓存和设置描述符映射的方法。但他们都没有工作。不确定它是否是预期的行为或错误地暴露了该API。

戈皮

答案 2 :(得分:0)

是的,持久性单元加载只进行一次。如果使用XMLMetadataSource更改映射,则必须使用EMF上的refreshMetadata()告知工厂刷新其映射,如下所述: http://wiki.eclipse.org/EclipseLink/DesignDocs/340192#Refresh

之后,获得的下一个EntityManagers将使用新的映射,而现有的EM仍将使用旧的映射。