可以使用@OrderColumn 注解。
public @interface OrderColumn
指定用于
保持列表的持久顺序。持久性提供者是
负责在检索和在
数据库。持久性提供者负责更新
在刷新到数据库时排序以反映任何插入,
影响列表的删除或重新排序。
OrderColumn 注释在 OneToMany 或 ManyToMany 上指定
关系或元素集合。 OrderColumn 注释
在引用的关系的一侧指定
要订购的集合。订单列不可见
实体或可嵌入类的状态的一部分。
OrderBy 注释应该用于可见的排序
持久状态并由应用程序维护。订购者
指定 OrderColumn 时不使用注解。
订单列必须是整型。持久性提供者
保持一个连续的(非稀疏的)排序的值
更新关联或元素集合时的 order 列。这
第一个元素的 order 列值为 0。
唯一的缺点是第一个元素的数字是0,而不是1
一个例子:
@Entity
@Table(name="STUDENT")
@SequenceGenerator(name="student_seq", initialValue=1,
allocationSize=10,sequenceName="STUDDENT_SEQ")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="student_seq")
private Long Id;
@Column(name="NAME")
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy="student")
@OrderColumn(name="FOLLOWUP_NUMBER")
private List<Book> books = new ArrayList<>();
...............
...............
}
@Entity
@SequenceGenerator(name="book_seq", initialValue=1,
allocationSize=10, sequenceName="BOOK_SEQ")
public class Book {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="book_seq")
private Long id;
@ManyToOne
@JoinColumn(name="STUDENT_ID")
private Student student;
@Column(name="TITLE", nullable=false)
private String title;
..................
..................
}
还有这个简单的测试用例:
EntityTransaction tr = em.getTransaction();
tr.begin();
for (int j = 1; j < 10; j++) {
Student student = new Student("Student name " + j);
for (int i = 1; i <= 10; i++) {
student.getBooks().add(new Book("Some book" + i, student));
}
em.persist(student);
}
tr.commit();
生成以下表格(在 Oracle 12c 和 Hibernate 5.2 上测试):
select * from student;
ID NAME
----- --------------------
1 Student name 1
2 Student name 2
3 Student name 3
4 Student name 4
.......
.......
select * from book
order by student_id, followup_number;
ID TITLE STUDENT_ID FOLLOWUP_NUMBER
----- -------------------- ---------- ---------------
1 Some book1 1 0
2 Some book2 1 1
3 Some book3 1 2
4 Some book4 1 3
5 Some book5 1 4
6 Some book6 1 5
7 Some book7 1 6
8 Some book8 1 7
9 Some book9 1 8
10 Some book10 1 9
11 Some book1 2 0
12 Some book2 2 1
13 Some book3 2 2
14 Some book4 2 3
15 Some book5 2 4
16 Some book6 2 5
17 Some book7 2 6
18 Some book8 2 7
19 Some book9 2 8
20 Some book10 2 9
21 Some book1 3 0
22 Some book2 3 1
23 Some book3 3 2
........
........
性能可能是另一个劣势,因为对于每一本书,Hibernate 生成两个 SQL 命令 - 一个插入,然后一个更新 FOLLOWUP_NUMBER 列。
更糟糕的是,当某本书被删除时,Hibernate 会生成所有再次为给定学生的数字并触发所有剩余书籍的FOLLOWUP_NUMBER 列的更新。
编辑
但困扰我的是“订单列作为
实体或可嵌入类的状态。”。数据和我一样
喜欢它在数据库中,但它没有反映到我的实体上。虽然我会
喜欢使用这个 FOLLOWUP_NUMBER
我不知道这在 JPA 中是否可行,但在这种情况下可以使用 Hibernate 扩展 @Formula:
class Book{
.......
.......
@Formula(value="FOLLOWUP_NUMBER")
private Long followUpNumber;
public Long getFollowUpNumber() {
return followUpNumber;
}
........
........
}
这个计算字段甚至可以被查询,例如下面的测试用例:
Query query = em.createQuery(
"Select b FROM Book b JOIN b.student s " +
"WHERE s.name = :studentname AND b.followUpNumber = :follownbr"
);
query.setParameter("studentname", "Student name 6");
query.setParameter("follownbr", Long.valueOf(4));
Book book = (Book)query.getSingleResult();
System.out.println("Found book = " + book.getTitle());
System.out.println("book follow nbr= " + book.getFollowUpNumber());
给出以下结果:
Found book = Some book5
book follow nbr= 4
Hibernate 使用以下 SQL 查找该书:
select
book0_.id as id1_0_,
book0_.STUDENT_ID as STUDENT_ID3_0_,
book0_.TITLE as TITLE2_0_,
book0_.FOLLOWUP_NUMBER as formula0_
from
Book book0_
inner join
STUDENT student1_
on book0_.STUDENT_ID=student1_.Id
where
student1_.NAME=?
and book0_.FOLLOWUP_NUMBER=?