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

Java 基于外键的增量字段(JPA、Hibernate、Oracle DB),java,oracle,hibernate,jpa,Java,Oracle,Hibernate,Jpa,是否可以基于外键自动增加字段?我希望通过JPA(Hibernate)和Oracle DB实现这一点。我已经读过,使用MySQL的InnoDB引擎是不可能的 这很像下面的问题: 但是这些仅仅基于MySQL表本身。不是JPA和Oracle DB 这正是我需要的,但遗憾的是没有答案 作为一个具体的例子,考虑一个简单的例子。每个学生都有多本书。Book有一个主键(常规增量),但也有一个followUpNumber。该数字从1开始,并自动递增,每次将书籍添加到学生。这意味着每个学生都有一个书

是否可以基于外键自动增加字段?我希望通过JPA(Hibernate)和Oracle DB实现这一点。我已经读过,使用
MySQL
InnoDB
引擎是不可能的

这很像下面的问题:

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

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

作为一个具体的例子,考虑一个简单的例子。每个学生都有多本书。

Book
有一个主键(常规增量),但也有一个
followUpNumber
。该数字从1开始,并自动递增,每次将
书籍
添加到
学生
。这意味着每个
学生
都有一个
书籍
列表,其中
后续编号每次从1开始。下面是
表,显示我的意思:

|------|------------|-----------------|
|  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是主键
  • 学生id是学生的外键
  • followup\u number是每个学生id从1开始的字段
是否存在不需要放置在主键字段上的自定义策略?我当前的解决方案是在添加一本新书之前,迭代所有的新书,获得最高的后续编号,并将该编号+1分配给新书。但我觉得必须有一种更干净、更优雅的方法来做到这一点。

可以使用注释

public@interface-OrderColumn

指定一列,该列用于 保持列表的持久顺序。持久性提供程序是 负责在检索时维护订单,并在 数据库持久性提供程序负责更新 刷新数据库以反映任何插入时进行排序, 影响列表的删除或重新排序

OrderColumn注释是在OneToMany或ManyToMany上指定的 元素集合上的关系或。OrderColumn注释 在引用的关系的一侧指定 要订购的集合。“订单”列不可见 实体或可嵌入类状态的一部分

OrderBy注释应用于显示为的排序 持久状态,并由应用程序维护。勤务员 指定OrderColumn时不使用注释

订单列必须为整型。持久性提供者 维护的值的连续(非稀疏)顺序 更新关联或元素集合时的顺序列。这个 第一个元素的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<>();

    ...............
    ...............
}

这个简单的测试用例:

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();
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());


性能可能是另一个缺点,因为对于每本书,Hibernate都会生成两个SQL命令—一个insert,然后更新
FOLLOWUP\u NUMBER
列。
更糟糕的是,当某本书被删除时,然后Hibernate再次为给定的学生生成所有数字,并为所有剩余的书籍触发
FOLLOWUP\u NUMBER
列的更新


编辑


但令我烦恼的是“订单列作为订单的一部分不可见” 实体或可嵌入类的状态。“。数据和我想的一样 就像在数据库中一样,但它不会反映到我的实体上。当我 我想利用这个跟进号码

我不知道这在JPA中是否可行,但在这种情况下可以使用Hibernate扩展
@Formula

class Book{
    .......
    .......

    @Formula(value="FOLLOWUP_NUMBER")
    private Long followUpNumber;

    public Long getFollowUpNumber() {
        return followUpNumber;
    }

    ........
    ........
}
甚至可以查询此计算字段,例如下面的测试用例:

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();
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=?

我想到了insert上的数据库触发器,它不需要由JPA解决。但我很想看到面向JPA的解决方案。很高兴看到JPA有一个可能的解决方案。但困扰我的是“order列作为实体或可嵌入类的状态的一部分是不可见的”。数据就像我希望它在数据库中一样,但它没有反映到我的实体上。虽然我想利用这个
FOLLOWUP\u NUMBER
@Formula
扩展可以用于这种情况,但我在答案后面附加了一个示例。
    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=?