![](/img/trans.png)
[英]Load ManyToOne Relation with Hibernate Envers - Eager/Lazy?
[英]Hibernate two ManyToOne relations on one Table, the first gets Eager and the second LAZY loaded
我有以下实体,一个最多可以有两个类别的item
,一个主要的和一个次要的。 使用JoinColumnsOrFormulas
将两个类别映射到ManyToOne
到category
表。 第一个按预期获取EAGER
,但第二个不会出现在 SQL 语句中并被延迟加载。 这种延迟加载会导致经典的 n+1 问题。
这是我的项目实体,其中包含应该加入的两个类别实体:
@Entity
@Table(name = "item", schema = "public", catalog = "stackoverflow_question")
@DynamicUpdate
public class Item extends StackOverflowQuestionEntity {
@Id
@Column(name = "id")
protected Long id;
@Column(name = "site")
private String site;
@ManyToOne
@JoinColumnsOrFormulas({
@JoinColumnOrFormula(formula = @JoinFormula(value = "site", referencedColumnName = "site")),
@JoinColumnOrFormula(formula = @JoinFormula(value = "primary_category_id", referencedColumnName = "category_id"))
})
private Category primaryCategory;
@Column(name = "primary_category_id")
private Long primaryCategoryId;
@ManyToOne
@JoinColumnsOrFormulas({
@JoinColumnOrFormula(formula = @JoinFormula(value = "site", referencedColumnName = "site")),
@JoinColumnOrFormula(formula = @JoinFormula(value = "secondary_category_id", referencedColumnName = "category_id"))
})
private Category secondaryCategory;
@Column(name = "secondary_category_id")
private Long secondaryCategoryId;
}
这是类别实体:
@Entity
@Table(name = "category", schema = "public", catalog = "stackoverflow_question")
public class Category extends StackOverflowQuestionEntity {
@Column(name = "category_id")
private Long categoryId;
@Column(name = "name")
private String name;
@Column(name = "site")
private String site;
}
结果查询仅包含主要类别:
SELECT this_.id AS id1_9_9_,
this_.inserted AS inserted2_9_9_,
this_.updated AS updated3_9_9_,
this_.primary_category_id AS formula174_9_,
this_.secondary_category_id AS formula176_9_,
category2_.id AS id1_0_0_,
category2_.inserted AS inserted2_0_0_,
category2_.updated AS updated3_0_0_,
category2_.name AS name7_0_0_
FROM public.item this_
LEFT OUTER JOIN public.category category2_ ON this_.site=category2_.site
AND this_.primary_category_id=category2_.category_id
WHERE True;
因此,次要类别变得懒惰:
SELECT category0_.id AS id1_0_0_,
category0_.inserted AS inserted2_0_0_,
category0_.updated AS updated3_0_0_,
category0_.name AS name4_0_0_,
category0_.site AS site5_0_0_
FROM public.category category0_
WHERE category0_.site=?
AND category0_.category_id=?;
为什么 Hibernate 加入次要类别懒惰,注解似乎是一样的。
我使用的休眠版本是 5.0.10.Final。
这是基本实体的样子:
@MappedSuperclass
abstract public class StackOverflowQuestionEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, insertable = true, updatable = false, nullable = false)
protected Long id;
@Type(type="LocalDateTime")
@Column(name = "created", nullable = false, insertable = true, updatable = false)
protected LocalDateTime created;
@Type(type="LocalDateTime")
@Column(name = "refreshed", nullable = false, insertable = true, updatable = true)
protected LocalDateTime refreshed;
@PreUpdate
protected void onUpdate() {
refreshed = now();
}
@PrePersist
protected void onCreate() {
created = refreshed = now();
}
}
这是一个示例“查询”,正如我所说我使用的是休眠标准和 HQL,这两种方法都会出现问题。
session
.createCriteria(Item.class)
.add(eq("id", id))
.uniqueResult();
使用标准 JPA 注释,它看起来像这样(更新):
@ManyToOne
@JoinColumns({
@JoinColumn(name="site", referencedColumnName="site", insertable = false, updatable = false),
@JoinColumn(name="primary_category_id", referencedColumnName="category_id", insertable = false, updatable = false)
})
private Category primaryCategory;
@ManyToOne
@JoinColumns({
@JoinColumn(name="site", referencedColumnName="site", insertable = false, updatable = false),
@JoinColumn(name="secondary_category_id", referencedColumnName="category_id", insertable = false, updatable = false)
})
private Category secondaryCategory;
更新:我发现第二个select
语句仅在您使用复合键join
时生成:Hibernate 尝试使用TwoPhaseLoad
解析{site=site, id=null}
的关联。 但是如果你写
@ManyToOne
@JoinColumn(name="secondary_category_id")
private Category secondaryCategory;
并且secondary_category_id
为null
则将生成唯一一个select
语句,并且secondaryCategory
值为null
。 也许它会以某种方式帮助你。 例如,您可以在构建条件时在site
字段上添加约束:
Category c = (Category) session.createCriteria(Category.class)
.add(Restrictions.eq("id", 1L)) // for example
// here you define additional restriction on site field
.createAlias("secondaryCategory", "sc", JoinType.LEFT_OUTER_JOIN, Restrictions.sqlRestriction("this_.site = {alias}.site"))
.uniqueResult();
尝试以下解决方案:
@Entity
@Table(name = "item", schema = "public", catalog = "stackoverflow_question")
@DynamicUpdate
public class Item {
@ManyToOne
@JoinColumn(name="site")
private Category primaryCategory;
@ManyToOne
@JoinColumn(name="site")
private Category secondaryCategory;
}
@Entity
@Table(name = "category", schema = "public", catalog = "stackoverflow_question")
public class Category {
@OneToMany(targetEntity=Item.class, mappedBy="primaryCategory", cascade=CascadeType.ALL)
private List<Item> primaryCategoryList;
@OneToMany(targetEntity=Item.class, mappedBy="secondaryCategory", cascade=CascadeType.ALL)
private List<Item> secondaryCategoryList;
}
我使用您的类和以下查询代码进行了快速测试(使用 JPA 条件查询而不是本机 Hibernate)
CriteriaQuery<Item> cq = em.getCriteriaBuilder().createQuery(Item.class);
EntityGraph<Item> entityGraph = em.createEntityGraph(Item.class);
entityGraph.addSubgraph("primaryCategory", Category.class);
entityGraph.addSubgraph("secondaryCategory", Category.class);
List<Item> items = em.createQuery(cq.select(cq.from(Item.class)))
.setHint("javax.persistence.loadgraph", entityGraph)
.getResultList();
导致生成以下 SQL(为便于阅读而格式化):
select item0_.id as id1_1_0_,
category1_.id as id1_0_1_,
category2_.id as id1_0_2_,
item0_.site as site4_1_0_,
item0_.primary_category_id as primary_2_1_0_,
item0_.secondary_category_id as secondar3_1_0_,
category1_.category_id as category2_0_1_,
category1_.name as name3_0_1_,
category1_.site as site4_0_1_,
category2_.category_id as category2_0_2_,
category2_.name as name3_0_2_,
category2_.site as site4_0_2_
from item item0_
left outer join category category1_
on item0_.site=category1_.site
and item0_.secondary_category_id=category1_.category_id
left outer join category category2_
on item0_.site=category2_.site
and item0_.primary_category_id=category2_.category_id
如您所见,两个类别表都在同一个 SELECT 中连接
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.