This tutorial shows you how to use Hibernate's @SQLOrder
annotation.
When fetching an entity using Hibernate, you may also want to fetch related collections defined in the entity. A collection itself can consist of more than one items. In some cases, the order of the items matters. As a result, it would be better if we can fetch the collection items in a desired order. For that purpose, you can use JPA's @OrderBy
column. However, if you need to write the order expression using native SQL syntax, you can use Hibernate's @SQLOrder
, which was introduced in Hibernate 6.3
Using @SQLOrder
Annotation
For example, there is an entity named SubCategory
.
@Entity
@Table(name = "sub_categories")
public class SubCategory {
@Id
@UuidGenerator
private UUID id;
private String name;
private int popularity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name ="category_id", nullable = false)
private Category category;
}
There is another entity named Category
. A category can have multiple sub categories and a sub category must belong to a category. In other words, the relationship between category and sub category is one-to-many. When a category is fetched, we also want to fetch its sub categories.
@Entity
@Table(name = "categories")
public class Category {
@Id
@UuidGenerator
private UUID id;
private String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private List<SubCategory> subCategories;
}
There is a requirement that the fetched sub categories must be ordered by the value of the productsCount
field. In the database, the column name is products_count
. To fulfill the requirement, you can add @SQLOrder
annotation to the collection field. On the annotation, you have to pass the order expression in native SQL format.
@Entity
@Table(name = "categories")
public class Category {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
@SQLOrder("products_count desc")
private List<SubCategory> subCategories;
// other fields
}
Below is the generated query.
select c1_0.id,c1_0.name,sc1_0.category_id,sc1_0.id,sc1_0.name,sc1_0.products_count
from categories c1_0 join sub_categories sc1_0
on c1_0.id=sc1_0.category_id
order by sc1_0.products_count desc
The SQL syntax may depend on the database that you use. It's also allowed to use multiple columns (e.g. @SQLOrder("products_count, other_column")
and SQL functions (.e.g. @SQLOrder("char_length(name)")
).
You're not allowed to define both @SQLOrder
and @OrderBy
annotations. If you do that, you'll get the following error.
Caused by: org.hibernate.AnnotationException: Collection 'com.woolha.hibernate6.example.model.Category.subCategories' is annotated both '@jakarta.persistence.OrderBy' and '@org.hibernate.annotations.OrderBy'
Summary
If you use Hibernate 6.3 or above, you can use the @SQLOrder
annotation to define the order of a collection when it's fetched. It requires you to write the order expression in native SQL format which can be useful if you want to write syntax or functions not supported by HQL/JPQL. If possible, using the @OrderBy
annotation is a more preferred way since you can write the expression in HQL/JPQL, which has a better compatibility with different database platforms.
You can also read about: