2016-07-12 11 views
2

外部キーに基づいてフィールドの自動インクリメントを使用することはできますか? JPA(Hibernate)とOracle DBでこれを実現したいと思います。私はMySQLInnoDBエンジンでは不可能だと読んだことがあります。外部キー(JPA、Hibernate、Oracle DB)に基づく増分フィールド

これはかなり、以下の質問のようなものです:

しかし、これらは唯一のMySQLテーブル自体に基づいています。 JPA & Oracle DBではありません。

私がまさに必要とされていますが、悲しいことに何の答えはありません。

具体例として、簡単な例を考えてみましょう。各Studentには複数のBookがあります。 Bookにはプライマリキー(通常増分)がありますが、followUpNumberもあります。この番号は1から始まり、追加されたそれぞれに対してBookStudentに自動増分します。意味はすべてStudentBookであり、そのうちのfollowUpNumberは毎回1から始まります。学生

  • followup_numberから始まるフィールドであることへの外部キーであることをSTUDENT_ID

    |------|------------|-----------------| 
    | 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が主キー
    • ている:ここで私が何を意味するか表示するBookテーブルです1人につき1個student_id

    プライマリキーフィールドに配置する必要のないカスタム@GeneratedValue戦略がありますか?私の現在の解決策は、新しいBookを追加する直前であり、Bookすべてを繰り返し、最高のfollowup_numberを取得し、その番号+ 1を新しいブックに割り当てます。しかし、私はこれを行うには、より洗練された、よりエレガントな方法がなければならないと感じています。

  • +0

    挿入時にデータベース・トリガーが頭に浮かぶ、それはJPAが解決しようとする必要はありません。しかし、私はJPA指向のソリューションを知りたいと思っています。 – Gimby

    答えて

    2

    @OrderColumn注釈を使用することができます。

    公共@interface OrderColumn

    は、リストの持続的な秩序を維持 に使用される列を指定します。持続性プロバイダは、検索時および データベースで注文の維持を担当する です。持続性プロバイダは、挿入を反映するためにデータベースにフラッシュするときに の順序を更新し、 の削除、または並べ替えがリストに影響します。

    OrderColumnアノテーションは、OneToManyまたはManyToMany リレーションシップまたは要素コレクションで指定されます。OrderColumn注釈 は、オーダーする コレクションを参照する関係の側で指定されています。指図列は、 エンティティまたは埋め込み可能クラスの状態の一部として表示されません。

    OrderBy注釈は、 永続状態として表示され、アプリケーションによって管理されている発注に使用する必要があります。 OrderBy 注釈は、OrderColumnが指定されている場合は使用されません。

    注文列は、一体型でなければなりません。持続性プロバイダ は、アソシエーションまたは要素コレクションを更新するときに、 注文列の値の連続した(疎でない)順序を維持します。

    @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<>(); 
    
        ............... 
        ............... 
    } 
    
    :最初の要素の 順序列の値は0

    唯一の欠点は、最初の要素の数は、例えば0ではなく1


    であることです


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

    は、次の表(オラクル12cの上でテストおよび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が2つのSQLコマンドを生成するからです。 FOLLOWUP_NUMBER列の更新。
    さらに悪いことに、一部の本が削除されると、Hibernateは特定の生徒のすべての番号を再度生成し、残っているすべての書籍についてFOLLOWUP_NUMBER列の更新を起動します。


    EDIT


    しかし、どのような私を気にすることは「注文の列がエンティティまたは埋め込み可能なクラスの 状態の一部として表示されません。」です。データはちょうど私が をDBで好きだが、それは私のエンティティに反映されていません。私は このFOLLOWUP_NUMBER

    の利用をしたいのですが、これは、JPAでpossibeある場合、私は知りませんが、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 
    

    や休止状態、その本を見つけるために、以下の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=? 
    
    +0

    JPAには解決策があります。しかし、気になるのは、「注文列は、エンティティまたは埋め込み可能クラスの状態の一部として表示されません。データはDB内のデータと同じですが、エンティティには反映されません。私はこの 'FOLLOWUP_NUMBER'を利用したいと思います。 – Jaims

    +0

    この例では '@ Formula'拡張を使用できますが、私は答えに例を追加しました。 – krokodilko

    関連する問題