假设我有一个像下面这样的实体,其中每个集合都是一个与PersonEntity主键具有外键关系的独立实体。使用Hibernate实体标准的现有表连接
PersonEntity - PK: person_id
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "person", orphanRemoval = true)
Set<AddressEntity> addresses
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "person", orphanRemoval = true)
Set<NameEntity> nameParts
AddressEntity和NameEntity都有一个PersonEntity,它是以实体形式表示的FK关系。
所有表格还有一个名为tenant_id的字段,它们被分区。
如果我创建HibernateCriteria像如下:
final Criteria criteria = sessionFactory.getCurrentSession().createCriteria(PersonEntity.class, "p");
criteria.add(Restrictions.eq("p.personId", personId));
criteria.add(Restrictions.eq("p.tenantId", tenantId));
我得到SQL这样的:
select ALL_ATTRIBUTES_SNIPPED
FROM person this_
LEFT OUTER JOIN address addresses2_
ON this_.person_id=addresses2_.person_id
LEFT OUTER JOIN name nameparts4_
ON this_.person_id=nameparts4_.person_id
WHERE this_.person_id=?
AND this_.tenant_id=?
望着解释计划,我看到,在做的时候加入这种检查所有分区。这是不必要的,因为它只需要查看一个分区。
我想在所有表上添加额外的限制,使得所有表都受到tenant_id的限制。所以SQL可能看起来像这样:
select ALL_ATTRIBUTES_SNIPPED
FROM person this_
LEFT OUTER JOIN address addresses2_
ON this_.person_id=addresses2_.person_id
LEFT OUTER JOIN name nameparts4_
ON this_.person_id=nameparts4_.person_id
WHERE this_.person_id=?
AND this_.tenant_id=?
AND addresses2_.tenant_id =?
AND nameparts4_.tenant_id =?
但是,我似乎无法弄清楚如何创建条件来执行此操作。当我尝试类似如下:
final Criteria criteria = sessionFactory.getCurrentSession().createCriteria(PersonEntity.class, "p")
.createAlias("addresses", "address", JoinType.LEFT_OUTER_JOIN)
.createAlias("nameParts", "namePart", JoinType.LEFT_OUTER_JOIN)
criteria.add(Restrictions.eq("p.personId", personId));
criteria.add(Restrictions.eq("p.tenantId", tenantId));
criteria.add(Restrictions.eq("address.tenantId", tenantId));
criteria.add(Restrictions.eq("namePart.tenantId", tenantId));
我得到的SQL,看起来像这样:
select ALL_ATTRIBUTES_SNIPPED
FROM person this_
LEFT OUTER JOIN address addresses2_
ON this_.person_id=addresses2_.person_id
LEFT OUTER JOIN name nameparts4_
ON this_.person_id=nameparts4_.person_id
LEFT OUTER JOIN address addresses3_
ON this_.person_id=addresses3_.person_id
LEFT OUTER JOIN name nameparts1_
ON this_.person_id=nameparts1_.person_id
WHERE this_.person_id=?
and this_.tenant_id = ?
and addresses3_.tenant_id = ?
and nameparts1_.tenant_id = ?
正如你所看到的,表的连接两次。
如何创建使用原始表的限制?我不明白我将如何提供访问现有联接的限制。我尝试了类似p.addresses.tenantId
,但它表示addresses
未被识别。
编辑:我已经在很大程度上解决了查询问题,通过将此行放置在Person实体中和设置实体中的PersonEntity(即AddressEntity)上。
@JoinColumns(value={
@JoinColumn(name="PERSON_ID", referencedColumnName="PERSON_ID", insertable=false, updatable=false),
@JoinColumn(name="TENANT_ID", referencedColumnName="TENANT_ID", insertable=false, updatable=false)
})
我还删除了这些列的mappedBy属性。
这强制加入person_id和tenant_id,并使解释计划成本显着提高(以及真实世界的性能)。但是,我不确定这是否是真正的解决方案,因为它引入了一个新问题。现在
我的问题是,当我尝试创建一个PersonEntity,我得到以下错误:
12:09:26.672 WARN [main] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1400, SQLState: 23000 12:09:26.672 ERROR [main] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-01400: cannot insert NULL into ("USER"."ADDRESS"."PERSON_ID")
会出现此即使SQL显示了人插入只是在地址插入尝试之前发生。好像person_id没有被传递到地址插入。我怎么能强迫Hibernate做到这一点?以前,它只是自动发生(从我的角度来看)。
我正在使用序列生成器来创建我的主键,如果这很重要。