2017-02-28 30 views
0

假设我有一个像下面这样的实体,其中每个集合都是一个与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和ten​​ant_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做到这一点?以前,它只是自动发生(从我的角度来看)。

我正在使用序列生成器来创建我的主键,如果这很重要。

回答

0

什么解决这对我来说是增加这些线路在PersonEntity集合,然后在儿童实体类(AddressEntity,NameEntity)的PersonEntity领域:

@ManyToOne(fetch = FetchType.EAGER)  
@JoinColumns(value={ 
      @JoinColumn(name = "PERSON_ID", referencedColumnName = "PERSON_ID", nullable = false), 
      @JoinColumn(name = "TENANT_ID", referencedColumnName = "TENANT_ID", nullable = false) 
      }) 
public PersonEntity getPerson() { 
     return personEntity; 
} 

,对于查询,但我的工作不能做插入或更新,所以我不得不做的另一件事是确保现有tenantId领域有插入=虚假和更新=假,就像这样:

@Column(name = "TENANT_ID", insertable = false, updatable = false) 
public String getTenantId() { 
    return tenantId; 
} 

然后,在执行的标准原来的问题会导致所有的子选项卡LES有对PERSON_ID和TENANT_ID联接,正是我想要的。

这改变了我的估计成本从2525到15的解释计划,因为它可以直接进入正确的分区,而不是通过他们的循环。

相关问题