java 使用 JPA 2.0 以编程方式加载实体类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2838634/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:05:48  来源:igfitidea点击:

Programmatically loading Entity classes with JPA 2.0?

javadynamicjpa-2.0entities

提问by wen

With Hibernate you can load your Entityclasses as:

使用 Hibernate,您可以将Entity类加载为:

sessionFactory = new AnnotationConfiguration()
                    .addPackage("test.animals")
                    .addAnnotatedClass(Flight.class)
                    .addAnnotatedClass(Sky.class)
                    .addAnnotatedClass(Person.class)
                    .addAnnotatedClass(Dog.class);

Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?

有没有办法做同样的事情——以编程方式加载你的实体类——以符合 JPA 2.0 的方式?

The reason for this question is because I'd like to dynamicallyload my Entityclasses, thus not necessarily programmatically.

这个问题的原因是因为我想动态加载我的Entity类,因此不一定以编程方式加载。

回答by Carl Horton

With the help of Spring I did this in a JPA compliant way.

在 Spring 的帮助下,我以符合 JPA 的方式做到了这一点。

My "persistence.xml" looks empty, with no entities listed within the <persistence-unit>element.

我的“persistence.xml”看起来是空的,<persistence-unit>元素中没有列出任何实体。

I then wrote a class that implemented PersistenceUnitPostProcessor like so:

然后我编写了一个实现 PersistenceUnitPostProcessor 的类,如下所示:

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.reflections.Reflections;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;

public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {

    private String reflectionsRoot;
    private Logger log = LoggerFactory.getLogger(ReflectionsPersistenceUnitPostProcessor.class);

    @Override
    public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
            Reflections r = new Reflections(this.reflectionsRoot, new TypeAnnotationsScanner());
            Set<String> entityClasses = r.getStore().getTypesAnnotatedWith(Entity.class.getName());
            Set<String> mappedSuperClasses = r.getStore().getTypesAnnotatedWith(MappedSuperclass.class.getName());

            for (String clzz : mappedSuperClasses)
            {
                    pui.addManagedClassName(clzz);
            }


            for (String clzz : entityClasses)
            {
                    pui.addManagedClassName(clzz);
            }

    }

    public String getReflectionsRoot() {
            return reflectionsRoot;
    }

    public void setReflectionsRoot(String reflectionsRoot) {
            this.reflectionsRoot = reflectionsRoot;
    }
}

Then I adjusted my spring context xml like this:

然后我像这样调整了我的 spring 上下文 xml:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                            <property name="showSql" value="false" />
                            <property name="generateDdl" value="true" />
                            <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
                    </bean>
            </property>
            <property name="persistenceUnitName" value="GenericPersistenceUnit"/>
            <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
            <property name="persistenceUnitPostProcessors">
                    <list>
                            <bean class="com.austinmichael.core.repository.ReflectionsPersistenceUnitPostProcessor">
                                    <property name="reflectionsRoot" value="com.austinmichael"/>
                            </bean>
                    </list>
            </property>
    </bean>

Note the registration of the ReflectionsPersistenceUnitPostProcessorin the persistenceUnitPostProcessors setting.

注意ReflectionsPersistenceUnitPostProcessor在persistenceUnitPostProcessors 设置中的注册。

And that's it. Every class with a JPA Entity or MappedSuperclassannotation on the classpath is added to the classpath. I had to give reflections the prefix of a package name to scan through which is why com.austinmichaelis there at all. You could register a second ReflectionsPersistenceUnitPostProcessorwith a different package name prefix if you want if your entities don't share a common package name prefix.

就是这样。MappedSuperclass在类路径上带有 JPA 实体或注解的每个类都被添加到类路径中。我不得不给反射一个包名的前缀来扫描,这就是为什么com.austinmichael存在。ReflectionsPersistenceUnitPostProcessor如果您的实体不共享公共包名称前缀,您可以使用不同的包名称前缀注册第二个。

But, this is now JPAVendor agnostic.

但是,这现在与 JPAVendor 无关。

回答by Pascal Thivent

Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?

有没有办法做同样的事情——以编程方式加载你的实体类——以符合 JPA 2.0 的方式?

No, this is not supported by JPA so you'll have to do this in a provider specific way. James Sutherland described the process for EclipseLink in this threadlike this:

不,这不受 JPA 支持,因此您必须以特定于提供程序的方式执行此操作。James Sutherland 在此线程中描述了 EclipseLink 的过程,如下所示:

You can access the EclipseLink ServerSessionfrom the EntityManagerFactoryImpl(getServerSession()), and use its' addDescriptor(ClassDescriptor)or addDescriptors()API to add EclipseLink ClassDescriptor. You will need to build the ClassDescriptormeta-data objects directly yourself (or use the Mapping Workbench to create them), as loading from JPA annotations or orm.xml would be more difficult.

您可以ServerSessionEntityManagerFactoryImpl( getServerSession())访问 EclipseLink ,并使用其addDescriptor(ClassDescriptor)addDescriptors()API 添加 EclipseLink ClassDescriptor。您需要ClassDescriptor自己直接构建元数据对象(或使用 Mapping Workbench 来创建它们),因为从 JPA 注释或 orm.xml 加载会更加困难。

Also have a look at this more recent threadfor more code sample (the API looks like a bit verbose).

还可以查看这个更新的线程以获取更多代码示例(API 看起来有点冗长)。

References

参考

回答by Bozhidar Batsov

I don't think there is such option - JPA supports scanning the classpath for entities or explicitly listing the entity classes in the persistence.xml. Since you're using hibernate as the persistence provider however you can always resort to hibernate code. Have a look at the HibernateEntityManagerand HibernateEntityManagerFactoryclasses. You can cast entity manager factories and entity managers to them and do the usual hibernate stuff.

我不认为有这样的选项 - JPA 支持扫描实体的类路径或在persistence.xml 中明确列出实体类。由于您使用 hibernate 作为持久性提供程序,因此您始终可以使用 hibernate 代码。看看HibernateEntityManagerHibernateEntityManagerFactory类。您可以将实体管理器工厂和实体管理器转换为它们并执行通常的休眠操作。