以下是我的域名模型的摘录,其文本版本为“我有合同,客户,合同客户和发票。发票可以直接链接到客户,也可以链接到合同”。
<class name="Invoice">
<many-to-one class="Contract" />
<many-to-one class="Client" />
</class>
<class name="Contract">
<set table="ContractClient" fetch="select" lazy="true">
<one-to-many class="ContractClient" />
</set>
</class>
<class name="ContractClient">
<many-to-one class="Contract" fetch="select" />
<many-to-one class="Client" cascade="none" fetch="select" />
</class>
<class name="Client">
<set table="ContractClient" fetch="select" lazy="true">
<one-to-many class="ContractClient" />
</set>
</class>
我有兴趣获取属于客户的发票清单,包括直接链接的发票和客户为其一方的合同。我有以下(有效):
return getCurrentSession().createCriteria(Invoice.class)
.createAlias("contract", "contract", JoinType.LEFT_OUTER_JOIN)
.createAlias("contract.contractClients", "contractClient", JoinType.LEFT_OUTER_JOIN)
.add(Restrictions.or(
Restrictions.eq("client.id", id),
Restrictions.eq("contractClient.client.id", id)))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
}
但是,生成的SQL存在很大的性能问题,因为(未显示)Contract有许多1:1的表和大量的fetch = join查找。此外,OR类杀死它。因此,我已经采用了针对这两种类型的单独查询方法(直接链接到客户的发票,以及通过合同链接到客户的发票)。我很难想出第二件作品。
由于JOINS和选定列的爆炸,我想避免加入合同。如果我自己用SQL编写,我会使用:
SELECT
*
FROM
Invoice i
LEFT OUTER JOIN ContractClient c ON i.contractId=c.contractId
WHERE
c.clientId=?
但是,我在Invoice和ContractClient之间没有Hibernate映射,所以我要么必须通过Contract(我不想要),要么这样做(产生子选择):
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(ContractClient.class)
.add(Restrictions.eq("client.id", id))
.setProjection(Projections.property("contract"));
return getCurrentSession().createCriteria(Invoice.class)
.add(Property.forName("contract").in(detachedCriteria))
.list();
生产:
SELECT
*
FROM
Invoice this_
WHERE
this_.contractId IN ( SELECT
this_.contractId AS y0_
FROM
ContractClient this_
WHERE
this_.contractClientId=?)
有没有办法让Hibernate生成更直接的JOIN?