我有一个名为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对于每个targetAssetId。
我一直在寻找答案,但我能找到的每个例子都只是简单的例子。
更新1:继续搜索,我终于找到了答案。我需要使用key-many-to-one而不是key-property。我还没有尝试加入,但其他一切看起来都是正确的,所以这应该是答案。
更新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。
答案 0 :(得分:0)
我发现了如何做到这一点。在我上面的情况下它将无法工作,因为我有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可以正确执行连接。结果将是包含每个条目的Object数组的List。 Object包含作为连接一部分的2个类。您必须使用(Object [])强制转换Object来访问元素,然后将每个元素转换为相应的类。
我建议不要使用这种方法,因为Hibernate也会尝试加载所有连接的类。通过上面的示例,我从TreeNode获得了一行,但它生成了19个select语句。我甚至尝试将连接类设置为延迟加载,它仍然生成所有选择。