java - 基于外键的增量字段(JPA、Hibernate、Oracle DB)

标签 java oracle hibernate jpa

是否可以根据外键实现字段自增?我想通过 JPA (Hibernate) 和 Oracle DB 来实现这一目标。我读过 MySQLInnoDB 引擎不可能实现这一点。

这很像以下问题:

但这些仅基于 MySQL 表本身。不是 JPA 和 Oracle DB。

正是我所需要的,但遗憾的是没有答案。

作为具体示例,请考虑一个简单的示例。每个学生都有多本书籍Book 有一个主键(定期递增),但它也有一个 followUpNumber。此数字从 1 开始,并针对每添加一个 StudentBook 自动递增。这意味着每个 Student 都有一个 Book 列表,其中 followUpNumber 每次都从 1 开始。这是 Book 表来显示我的意思:

|------|------------|-----------------|
|  id  | student_id | followup_number |
|------|------------|-----------------|
|  1   |      1     |        1        |
|  2   |      1     |        2        |
|  3   |      1     |        3        |
|  4   |      2     |        1        |
|  5   |      1     |        4        |
|  6   |      1     |        5        |
|  7   |      2     |        2        |
|  8   |      3     |        1        |
|  9   |      3     |        2        |
|------|------------|-----------------|
  • id为主键
  • student_id 是学生的外键
  • followup_number 是每个 student_id 的从 1 开始的字段

有没有类似定制的@GeneratedValue不需要放在主键字段上的策略?我当前的解决方案是在添加新的 Book 之前,迭代所有 Book,获取最高的 followup_number 并将该数字 + 1 分配给新书。但我觉得必须有一种更干净、更优雅的方式来做到这一点。

最佳答案

@OrderColumn可以使用注解。

public @interface OrderColumn

Specifies a column that is used to maintain the persistent order of a list. The persistence provider is responsible for maintaining the order upon retrieval and in the database. The persistence provider is responsible for updating the ordering upon flushing to the database to reflect any insertion, deletion, or reordering affecting the list.

The OrderColumn annotation is specified on a OneToMany or ManyToMany relationship or on an element collection. The OrderColumn annotation is specified on the side of the relationship that references the collection that is to be ordered. The order column is not visible as part of the state of the entity or embeddable class.

The OrderBy annotation should be used for ordering that is visible as persistent state and maintained by the application. The OrderBy annotation is not used when OrderColumn is specified.

The order column must be of integral type. The persistence provider maintains a contiguous (non-sparse) ordering of the values of the order column when updating the association or element collection. The order column value for the first element is 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 列的更新。


编辑


But what bothers me is "The order column is not visible as part of the state of the entity or embeddable class.". The data is just as I'd like it in the DB, but it isn't reflected onto my entity. While I'd like to make use of this 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=?

关于java - 基于外键的增量字段(JPA、Hibernate、Oracle DB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38324986/

相关文章:

regex - Ora 06512/04088 在 INSERT INTO 语句时触发错误

java - hibernate 级联 : should setting to null on a parent delete children?

java - 如何在 Spring 批处理作业的下一步中获取上一步执行的 ID?

java - 当我能够通过 FileZilla 连接时,我无法从 SFTP 文件源中提取文件

mysql - SQL IN 查询近似值

java - 指定 jre 绝对路径时 Oracle setup.exe 空间敏感度

java - MVC 模板项目看不到 hibernate.cfg.xml

java - 我如何使用 hibernate 生成迁移?

java - Derby - java.sql.SQLException : Column 'table.column_name' not found

java - GET 始终返回 0 id 值。 Spring数据JPA