I have got the following Entities, an item
which can has up to two categories, a primary and a secondary.
Both categories are mapped ManyToOne
to the category
table using a JoinColumnsOrFormulas
.
The first one gets fetched EAGER
as expected, but the second one does not occur in the SQL statement and gets lazy loaded.
This lazy loading results in a classical n+1 problem.
This is my item entity with the both category entities which should gets joined:
@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;
}
This is the category entity:
@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;
}
The resulting query contains only the primary category:
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;
Hence the secondary category get joined lazy:
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=?;
Why is Hibernate joining the secondary category lazy, the annotations seems the be the same.
The hibernate version I am using is 5.0.10.Final.
This is how the base entity looks like:
@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();
}
}
Here is an example "query", as said I am using hibernate criteria as well as HQL, the problem occurs with both methods.
session
.createCriteria(Item.class)
.add(eq("id", id))
.uniqueResult();
Item
s? – UnderbodiceItem
s? Is it just"from Item"
, or something more involved? Also, please provide the source for yourStackOverflowQuestionEntity
, and maybe add the results of your research on using JPA annotations, if you have anything definite there yet – LalaStackOverflowQuestionEntity
base class to the question. I am fetching the items with HQL and Hibernate criteria, currently I am using the criteria for testing. Using the JPA Annotaions produces the correct query with both joins, but in cases where the secondary category is null hibernates tries to lazy fetch it… . – Cyclostylesecondary_category_id
isnull
or that it's not null but the entity with such id is not present? – Luralurch{site=site, id=null}
usingTwoPhaseLoad
– Luralurchsecondary_category_id
isnull
. – Cyclostyle