使用JPA和Hibernate在ORM.xml中定义命名查询

20
我正在尝试将我的命名查询放在orm.xml中(与persistence.xml一起放在META-INF目录下),但是Hibernate / JPA好像忽略了我的orm.xml。
当我尝试使用em.createNamedQuery("myQuery")创建我的命名查询时,它返回找不到这个查询的错误。
我正在使用注释,并且希望将我的命名查询外部化为orm.xml(仅此而已)。
以下是我的persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
    <mapping-file>META-INF/orm.xml</mapping-file>

    <class>com.mysite.Account</class>

    <properties>
        <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />
        <property name="hibernate.cache.use_query_cache" value="true" />
        <property name="hibernate.cache.use_second_level_cache" value="true" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="use_sql_comments" value="false" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.MYSQLDialect" />
        <property name="hibernate.c3p0.min_size" value="5" />
        <property name="hibernate.c3p0.max_size" value="20" />
        <property name="hibernate.c3p0.timeout" value="300" />
        <property name="hibernate.c3p0.max_statements" value="50" />
        <property name="hibernate.c3p0.idle_test_period" value="3000" />

        <property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider" />
    </properties>

</persistence-unit>

</persistence>

这是我的orm.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

<package>com.mysite</package>

<entity class="Account">
    <sql-result-set-mapping name="nicknames">
        <column-result name="nickname" />
    </sql-result-set-mapping>
    <table name="Account" />
    <named-native-query name="myQuery" result-set-mapping="nicknames">
        <query><![CDATA[select a.nickname from Account a]]>
    </query>
    </named-native-query>
</entity>
</entity-mappings>

我做错了什么?为什么我的 orm.xml 被忽略了?

谢谢


你的 Account 是否成功映射?也就是说,你能否像这样查询:em.find(Account.class, someId) - Bozho
1
是的,我的账户已经很好地映射了,因为我成功地使用了注解。 - Jerome Cance
4个回答

11

好的,我终于明白了!

我一直把我的 orm.xml 文件保存在 META-INF 目录中。当我把这个文件移到我的域对象所在的包中(就像我的例子中的 com.mysite 一样),orm.xml 就不会被忽略并且所有运行正常。

我还需要更改映射文件 (persistence.xml) 中的路径:com/mysite/orm.xml


1
@Jerome C. 很好知道(+1)。我会尝试它。 - Arthur Ronald
因为这是解决问题的答案 ;) - Jerome Cance

5
您的 orm.xml 文件中有一个小错误,导致整个文件不可用。问题在于元素声明的顺序必须符合相应的 XML 模式(特别是 http://java.sun.com/xml/ns/persistence/orm_1_0.xsd)。您可以通过运行 xml 代码经过支持 xml 模式的验证器来轻松检查。下面是已纠正的 orm.xml 版本,一定能完美工作,请参考。
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="
                     http://java.sun.com/xml/ns/persistence/orm
                     http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
                 version="1.0">

    <package>com.mysite</package>

    <entity class="Account">
        <table name="Account" />
        <named-native-query name="myQuery" result-set-mapping="nicknames">
            <query><![CDATA[
            select a.nickname from Account a
            ]]></query>
        </named-native-query>
        <sql-result-set-mapping name="nicknames">
            <column-result name="nickname" />
        </sql-result-set-mapping>
    </entity>
</entity-mappings>

2

正如所说的

当我尝试使用em.createNamedQuery("myQuery")创建我的命名查询时,它返回找不到此查询

你是正确的。但你忘记了以下内容

如果你把一个命名查询定义放在一个 <named-query> 元素中,而不是根元素中,它会以实体类名为前缀

所以你需要这样调用你的 namedQuery:

 em.createNamedQuery("Account.myQuery")

我很好奇:你的Account类是否存储在根类路径中?如果不是,你需要修复它丢失的包。假设Account类存储在br.com.hibernate.model.domain.Account中。那么你应该将实体声明为:

<entity class="br.com.hibernate.model.domain.Account" instead

您需要调用您的namedQuery,如下:

em.createNamedQuery("br.com.hibernate.model.domain.Account.myQuery") instead

建议:当您使用Hibernate作为持久性提供程序时,您不需要在persistence.xml文件中定义实体类。

祝好!


不错,我就怀疑是这样的,但在xsd中没有找到解释。能否提供链接到写有此内容的文档?是规范吗? - Bozho
@Bohzo 好的,Bohzo。Java Persistence with Hibernate书籍:在XML元数据中定义命名查询。除此之外,JPA规范也提到了它。 - Arthur Ronald
那个程序无法运行。我已经尝试了所有的解决方案。对于完整的路径名,我认为包标签在这里是用来指定默认包的,当你命名一个实体时使用,不是吗? 为了简化,我也尝试将命名查询放在根实体映射标签中,但没有结果。就像我说的,orm.xml被忽略了,因为如果我在xml中创建一个错误(没有结束标记),在hibernate启动时我没有收到任何错误... - Jerome Cance
<package> 元素允许不使用完全限定名称。 - Pascal Thivent

0

"META-INF/orm.xml" 是默认的映射文件,任何符合 JPA 标准的实体管理器都会查找它。

事实上,如果您的映射文件是 "META-INF/orm.xml",则无需在 persistence.xml 中定义它。

这是 hibernate 配置手册对此的说明:

class 元素指定了一个符合 EJB3 标准的 XML 映射文件。该文件必须在类路径中。根据 EJB3 规范,Hibernate EntityManager 将尝试加载位于 META_INF/orm.xml 的 jar 文件中的映射文件。当然,任何显式的映射文件也将被加载。实际上,您可以在映射文件元素中提供任何 XML 文件,即 hbm 文件或 EJB3 部署描述符。

参考:Hibernate 配置


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接