java - Hibernate 无法使复合键正常工作

标签 java hibernate

我有一个名为 WebAsset 的类:

public class WebAsset {
    private Long id;
    private String url;
    private int status;
    //more fields that are not relevent
}

我需要能够显示 WebAsset 之间的关系,因此我为关系创建了一个表和一个复合键类。

public class WebAssetReferencePK {
    private Long sourceAssetId;
    private Long targetAssetId;
}

public class WebAssetReference {
    private WebAssetReferencePK wpk;
    private Long updateTime;
}

我们被迫使用旧版本的 Hibernate,因此我们需要使用 xml 文件而不是注释。这是引用类的映射:

<class name="ca.gc.cra.www.crawler.valueobject.WebAssetReference" table="webassetreference">
    <composite-id name="webAssetReferencePK" class="ca.gc.cra.www.crawler.valueobject.WebAssetReferencePK">
        <key-property name="sourceAsset" type="java.lang.Long" column="sourceAssetId" />
        <key-property name="targetAsset" type="java.lang.Long" column="targetAssetId" />
    </composite-id>
    <property name="updateTime" type="java.lang.Long" column="updatetime" not-null="true" />
</class>

在复合键中,我得到了我在数据库中期望的内容,其中有 2 个相互关联的 ID。但是当我尝试使用 HQL 或 Criteria 查询时,它不起作用,因为 PK 类和 WebAsset 之间没有直接关系,我需要能够在 WebAsset 和 WebAssetReference 之间进行连接。如果我尝试将复合键类型从 java.lang.Long 更改为 WebAsset,则 hibernate 会将整个对象存储在 WebAssetReference 表中,而不仅仅是 ID。

我正在尝试做的一个例子是,如果我有一个 sourceAssetId,我想返回具有相同来源的所有 targetAssetId,但我不想要 ID 本身,我想要 WebAsset,它是每个 ID 的主键targetAssetId.

我一直在四处寻找答案,但我能找到的每个示例都只是不相关的简单示例。

更新 1:通过不断的搜索,我终于找到了答案。我需要使用多对一键而不是键属性。我还没有尝试加入,但其他一切看起来都不错,所以这应该是答案。

更新 2:无法使查询与 HQL 一起使用。这是我正在尝试执行的 SQL:

select * from webasset as wa join webassetreference as war on war.targetassetid=wa.webasset_id where war.sourceassetid=?

这是不起作用的 HQL:

FROM WebAsset JOIN WebAssetReference WebAssetReference.WebAssetReferencePK.targetAsset=WebAsset WHERE WebAssetReference.WebAssetReferencePK.sourceAsset = :sourceAsset

我在 HQL 中收到以下错误:错误 - 第 1:89 行:意外标记:.

我会继续尝试,但我似乎无法弄清楚 HQL。

最佳答案

我发现了如何做到这一点。在我上面的情况下,它将不起作用,因为我有 2 列连接到同一个表。但是,如果我使用上面相同的 WebAsset 类,而是使用此类:

 public class TreeNode implements Comparable<TreeNode>{

    private String nodeUrl;
    private Long id;
    private Boolean folder;
    private transient WebAsset nodeAsset = null; 
}

使用这个 .hbm.xml 文件:

<class name="ca.gc.cra.www.crawler.valueobject.TreeNode" table="TreeNode">
    <id name="id" type="java.lang.Long" column="treenode_id" >
        <generator class="identity"/> 
    </id>
    <many-to-one name="nodeAsset" class="ca.gc.cra.www.crawler.valueobject.WebAsset" column="nodeAsset_id" lazy="false" not-null="false" cascade="none" unique="true" />
    <property name="folder" type="java.lang.Boolean" column="folder" not-null="true" />
    <property name="nodeUrl" length="512"  type="java.lang.String" column="nodeUrl" not-null="true" />

    <set name="children" table="TreeNode" inverse="false" lazy="true" >
        <key column="parentnode_id"/>
            <one-to-many class="ca.gc.cra.www.crawler.valueobject.TreeNode" />
    </set>
</class>

然后您可以使用此代码来检索连接:

Session session = HibernateUtil.getSession();
try {
    String hql = "FROM TreeNode tn JOIN tn.nodeAsset WHERE tn.id=5";
    Query query = session.createQuery(hql);
    List result = query.list();
    System.out.println("done");
} catch (HibernateException e) {
    e.printStackTrace();
    throw new Exception("Query failed", e);
} finally {
    session.flush();
    session.close();
}

然后 Hibernate 可以正确地执行连接。结果将是一个包含每个条目的对象数组的列表。该对象包含属于联接的 2 个类。您必须使用 (Object[]) 强制转换对象以访问元素,然后将每个元素强制转换为适当的类。

我不建议使用这种方法,因为 Hibernate 也会尝试加载所有连接的类。在上面的示例中,我从 TreeNode 获取了 1 行,但它生成了 19 个选择语句。我什至尝试将连接的类设置为延迟加载,它仍然会生成所有选择。

关于java - Hibernate 无法使复合键正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23958048/

相关文章:

hibernate - JavaTypeDescriptorRegistry - 找不到所请求的 Java 类的匹配类型描述符

java - 如何在Java中通过格式化来居中字符串?

java - 如何将 HQL 中引用的实体转换为其子类

java - 具有列表 getter 的 Hibernate HQL

java - JPA:同一实体上的多对多关系

java - 带有 base64 图像的 HTML 到 PDF 抛出 FileNotFoundException

基于 Java 的 SIP 端点

java - 在 odata4j 库中扩展 olink

java - restFB AccessToken 无法解析为类型

java - Spring 事务传播和乐观锁定的问题