- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用 Spring Boot、Groovy 和 JPA/Hibernate 来迁移旧应用程序。唯一的限制是数据库模型不得更改,我发现自己遇到了一种奇怪的情况,其中存在 OneOnOne 关系:
请查看以下模型设置:
@Entity
@Table(name='table1')
class Table1 {
@Id
Table1Id id
@Column(name='sequence_num')
Integer seqNum
@Column(name='item_source')
String itemSource
@Column(name='source_type')
String sourceType
@OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name='key_field_2', insertable=false, updatable=false)
@NotFound(action=NotFoundAction.IGNORE)
// @Fetch(FetchMode.JOIN)
Table2 table2
}
@Embeddable
class Table1Id implements Serializable {
@Column(name='key_field_1')
String key1
@Column(name='key_field_2')
String key2
}
@Entity
@Table(name='table2')
class Table2 {
@Id
@Column(name='key_id')
String keyId
@Column(name='field1')
String field1
@Column(name='field2')
String field2
@Column(name='field3')
String field3
}
我的 Spock 测试如下:
def "Try out the JOIN select with Criteria API"() {
given:
CriteriaBuilder cb = entityManager.getCriteriaBuilder()
CriteriaQuery<Object[]> cQuery = cb.createQuery(Object[].class)
Root<Table1> t1 = cQuery.from(Table1.class)
Path<Table2> t2 = t1.get('table2')
Join<Table1, Table2> lanyonLeftJoin = t1.join('table2', JoinType.INNER)
Predicate where = cb.equal(t1.get('itemSource'), 'ABC')
cQuery.multiselect(t1, t2)
cQuery.where(where)
when:
List<Object[]> result = entityManager.createQuery(cQuery).getResultList()
then:
result.each{ aRow ->
println "${aRow[0]}, ${aRow[1]}"
}
}
此配置成功在 Table1 和 Table2 之间生成 INNER JOIN,请注意,即使是“where”子句中的常量也能正确解释。
但是,由于某些奇怪的原因,Table2 会重新查询第一个查询中返回的每一行。
我看到的输出是:
Hibernate:
select
table10_.key_field_1 as key_field_11_3_0_,
table10_.key_field_2 as key_field_22_3_0_,
table21_.key_id as key_id1_5_1_,
table10_.item_source as item_source3_3_0_,
table10_.sequence_num as sequence_num4_3_0_,
table10_.source_type as source_type5_3_0_,
table21_.field2 as field23_5_1_,
table21_.field3 as field34_5_1_,
table21_.field1 as field15_5_1_
from
table1 table10_
inner join
table2 table21_
on table10_.key_field_2=table21_.key_id
where
table10_.item_source=?
Hibernate:
select
table20_.key_id as key_id1_5_0_,
table20_.field2 as field23_5_0_,
table20_.field3 as field34_5_0_,
table20_.field1 as field15_5_0_
from
table2 table20_
where
table20_.key_id=?
Hibernate:
select
table20_.key_id as key_id1_5_0_,
table20_.field2 as field23_5_0_,
table20_.field3 as field34_5_0_,
table20_.field1 as field15_5_0_
from
table2 table20_
where
table20_.key_id=?
// 500+ more of these
正如我们所看到的,第一个查询成功返回了两个表中的所有行,它实际上正是我正在寻找的查询。然而,正在执行所有这些不必要的额外查询。
JPA 会这样做有什么原因吗?有没有办法阻止它?
我觉得我在这里遗漏了一些非常明显的东西。
预先感谢您的帮助
更新1
如果我更换
cQuery.multiselect(t1, t2)
对于
cQuery.multiselect(t1.get('id').get('key1'), t1.get('id').get('key2'),
t1.get('fieldX'), t1.get('fieldY'), t1.get('fieldZ'),
t2.get('fieldA'), t2.get('fieldB'), t2.get('fieldC') ...)
它生成完全相同的内连接查询,并且不会再次重新查询 Table2。
换句话说,看起来(至少对于这种情况)我需要显式列出两个表中的所有字段。这不是一个很好的解决方法,因为对于具有大量字段的表来说,它很快就会变得非常难看。我想知道是否有一种方法可以检索所有 @Column 注释的字段/getter,而无需资源到一堆反射内容?
最佳答案
我想我已经做到了!
@JoinFormula:
Table2 中的主键是 INT,Table1 中用作 FK 的字段是 String(我完全错过了!废话!)。因此,解决方案是应用 @JoinFormula 而不是 @JoinColumn,其形式为:
@OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumnsOrFormulas([
@JoinColumnOrFormula(formula=@JoinFormula(value='CAST(key_field_2 AS INT)'))
])
@NotFound(action=NotFoundAction.IGNORE)
Table2 table2
这会奇怪地返回一个 List
加入获取:
根据您的建议,我在查询中添加了“join fetch”,所以它看起来像:
select t1, t2 from Table1 t1 **join fetch** t1.table2 t2 where t1.itemSource = 'ABC'
这会导致 Hibernate 正确返回 List
单独使用 @JoinFormula 或 @JoinFormula +“join fetch”hibernate 停止生成 n+1 查询。
调试 Hibernate 代码我发现它在第一次使用联接查询查询数据库时可以正确检索并在 session 中存储两个实体,但是 PK 和 FK 数据类型之间的差异导致 Hibernate 再次重新查询数据库,在第一个查询中检索的每行一次。
关于java - Spring JPA + Hibernate OneToOne 关系进行 n+1 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41730665/
使用 Entity entity = hibernateTemplate.get(Entity.class, id); 当我点击 entity.getChild() 这是一个 OneToOne 关系时
我刚开始玩弄 Doctrine ORM 库,我正在学习表之间的所有关联。 所以我坚持单向和双向关系的差异。 据我所知,单向关系只有一侧有主键,那一侧是拥有一侧,对吧?双向关系在两个表中都有主键,因此您
我只用@OneToOne 注释我的字段,当我检查数据库(使用 liquibase 生成)时发现数据库列有唯一约束。 这是否意味着@OneToOne 本身就意味着唯一性,例如。一栋建筑只能在一个城市,其
当我同步我的数据库时,我收到了 的错误module' 对象没有属性 'OneToOnefield' models.py 的代码如下: from django.db import models from
我们想使用不在主表中但在从表中的外键创建单向@OneToOne映射。通过提供以下Java代码,Hibernate尝试在表product_ID中找到product列,但在productimage中找不到
我有以下问题。我有 3 个实体,我正在使用 OneToOne 单向: 实体 1 @Entity public class Entity1 implements Serializable{ @Id
我有 2 个类:User 和 UserPicture,它们具有 1:1 关系。 public class User { @Id @GeneratedValue(strategy=G
考虑以下数据库结构 我需要像这样实现单向一对一映射(结构已简化): @Entity @Table(name = "entity") public class Customer { @Id
我有一个实体:HtmlElement,与实体有以下@OneToOne关系:Component 查询参数实体: @Id @Column(name = "QUERY_PARAMETER_ID") priv
我有两个例子,第一个是@OneToOne单向映射,第二个是双向映射。在单向映射中,拥有方表必须包含引用对方表id的连接列;那么在双向中,它们都必须包含彼此的外键列。但是使用自动生成策略生成数据库模式后
我尝试使用 @OneOnOne 关系创建两个表(主表和辅助表) 。(我使用的是 Postgres ) 我这样定义初级表: Class Table1{ @GeneratedValue @Id @Colu
我想创建一个 @OneToOne 映射,其中根实体通过外键约束引用子实体。 @Entity public class MainEntity { @Id private long id;
我有以下实体: //The class Entity is a @MappedSuperclass with id, audit fields, equals and so on. @Entity p
我创建实体 Developer 和 TalentFile,我希望一个开发人员有一个文件 (Cv),当我设置实体时,我已经提交了 null /** * Developers * * @ORM\Table
我正在使用 play 框架 (v2.3.1),并且我有 2 个模型对象;用户和位置。他们彼此之间存在一对一的关系。保存按预期进行,但是当我想从数据库中检索用户时,该位置为空。 我的类(class):
关系所有者中的双向一对一映射是否需要 unique=true? @Entity public class Customer { @Id @GeneratedValue(strategy
我是 UML 图的新手,想编写下面的代码,其中有一个 OneToOne 双双向关联,带有 JPA 注释。 上下文:有个人和团队。每个团队由人组成,每个人只能属于一个团队。团队总是有一个人充当主要领导者
我正在尝试使用 JPA/Hibernate 设置下表: User: userid - PK name Validation: userid - PK, FK(user) code 可能有很多用户,每个
OneToOne 垂直扩展表字段是很常见的方法, 主表存商品资料, 分表存每个客户对应商品的备注和个性化的价格等等, 本文使用Blazor一步步实现这个简单的需求. 1. 基于 实战 10分
假设我有一个 Person 实体和一个 Animal 实体;一个人可以有两个最喜欢的动物,一个动物只能有一个 人喜欢他们的人(一个人喜欢一种动物使得其他人不再可能喜欢/看到该动物)。它是一个@OneT
我是一名优秀的程序员,十分优秀!