2016-11-21 18 views
2

私は親テーブル、すなわち、単一の列IDを含むaudit_log(親)を持っています。 audit_logの特定のIDに対して、私はベンダーIDのリストを持っています。私は別のテーブルaudit_log_vendorid(子テーブル)にそれらを格納しています。私は、子テーブルが親テーブルからid(parent_id)の1つを取得するようにします。テーブルスキーマは次のとおりです。Hibernate JPA親子マッピング

AUDIT_LOG audit_log_vendoridため

@Entity 
@Table(name="audit_log") 
public class AuditLog { 

private List<AuditVendorPair> vendorIDs; 


public AuditLog(List<AuditVendorPair> vendorIds) throws Exception { 
    this.vendorIDs = vendorIDs; 
} 

@OneToMany(cascade=CascadeType.ALL) 
@JoinTable(name = "audit_log_vendorid", 
    joinColumns = { @JoinColumn(name = "parent_id", referencedColumnName="id") }) 
public List<AuditVendorPair> getVendors() { 
    return vendorIDs; 
} 

@Id @Column(name="ID") 
public Long getId() { 
    return super.getId(); 
} 

public void setHostServices(List<AuditVendorPair> vendorIDs){ 
    this.vendorIDs = vendorIDs; 
} 

} 

マイHibernateマッピングクラスを以下のようにI'haveが私の休止状態のクラスを定義し

+-----------+------------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+-----------+------------+------+-----+---------+----------------+ 
| id  | bigint(19) | NO | PRI | NULL | auto_increment | 
| vendor_id | bigint(19) | NO |  | NULL |    | 
| parent_id | bigint(19) | NO |  | NULL |    | 
+-----------+------------+------+-----+---------+----------------+ 

+-------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+------------+------+-----+---------+-------+ 
| id | bigint(19) | NO | PRI | NULL |  | 
+-------+------------+------+-----+---------+-------+ 

audit_log_vendoridは以下の通りです。私はベンダーIDを渡し、他の2つのフィールドに休止状態が設定されることを期待します。 parent_idフィールドは、audit_logの "id"フィールドから取得します。これは現在mysqlの制約例外を引き起こしているので、nullとして初期化されています。

@Entity 
@Table(name="audit_log_vendorid") 
public class AuditVendorPair { 

private Long id; 
private Long parent_id; 
private Long vendor_id; 
public AuditVendorPair(Long vendor_id){ 
    this.vendor_id = vendor_id; 
} 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name="id") 
public Long getId(){ 
    return id; 
} 

public void setId(Long id){ 
    this.id = id; 
} 

@Column(name="vendor_id") 
public Long getVendorID() { 
    return vendor_id; 
} 

public void setVendorID(Long vendor_id){ 
    this.vendor_id = vendor_id; 
} 


@Column(name="parent_id") 
public Long getParentId() { 
    return parent_id; 
} 

public void setParentId(Long parentID){ 
    this.parent_id = parentID; 
} 
} 

私の注釈が正しいかどうか不思議です。私は基本的には、audit_logテーブルのidを、hibernateによってaudit_log_vendoridテーブルのparent_idフィールドに設定したいと考えています。

答えて

1

いいえ、正しくありません。 audit_log_vendoridは結合テーブルではありません。結合テーブルは、エンティティにマップされておらず、他のテーブルにマッピングされた2つの関連エンティティのIDを含むテーブルです。

また、AuditVendorPairにparent_idフィールドを設定しないでください。これはJavaの命名規則を尊重するだけでなく、ManyToOneでマップされたAuditLogへの参照に置き換える必要があるためです。

したがって、要するに、the documentationで説明されているようにマッピングされた双方向のOneToManyアソシエーションが必要です。

+0

はいaudit_log_vendoridは結合テーブルではありません。 ManyToOneでマップされたAuditLogを参照する理由は何ですか?私は単方向のoneToManyが動作すると思った。外部キーを使用して、参照された列からparent_idの値をフェッチする必要があることを休止状態にしていますか? audit_logテーブルのプライマリキーがIDを超えていると状況は変わりますか? – skeptic01

+0

一方向のOneToManyを使用できますが、audit_log_vendoridのparent_id列はOneToManyアソシエーション( '@JoinColumn(" parent_id ")'が必要です)によって処理され、AuditVendorPairエンティティで2回目にマッピングされるべきではありません。 AuditVendorPairエンティティから親にアクセスする必要がある場合は、双方向である必要があります。 –

1

私は、エンティティがオブジェクトであるJPAの主要な概念を見落としていると思います。そのため、エンティティはIDを直接使用するエンティティを参照することはありません。オブジェクトを参照します(JPAはidを使用します)。

@Entity 
@Table(name="audit_log") 
public class AuditLog { 

    @OneToMany(cascade= CascadeType.ALL, mappedBy = "auditLog") 
    private Collection<AuditVendorPair> vendorIDs; 

    @Id @Column(name="id") 
    private Long id; 

    public AuditLog() { 
    } 

    public Collection<AuditVendorPair> getVendors() { 
     if (vendorIDs == null) { 
      vendorIDs = new ArrayList<>(); 
     } 
     return vendorIDs; 
    } 

    public long getId() { 
     return id; 
    } 
} 

@Entity 
@Table(name = "audit_log_vendorid") 
public class AuditVendorPair { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id") 
    private Long id; 

    @JoinColumn(nullable = false, name = "parent_id") 
    @ManyToOne(optional = false) 
    private AuditLog auditLog; 

    @Column(name = "vendor_id") 
    private Long vendorId; 

    public AuditVendorPair() { 
    } 

    public long getVendorId() { 
     return vendorId; 
    } 

    public void setVendorId(long vendorId) { 
     this.vendorId = vendorId; 
    } 

    public AuditLog getAuditLog() { 
     return auditLog; 
    } 

    public void setAuditLog(AuditLog auditLog) { 
     this.auditLog = auditLog; 
    } 
} 

)DBを照会AuditVendorPairは、エンティティを使用して監査ログを参照している、これは実体の関係であることから、あなたは名前を指定するために@JoinColumnを使用する必要があります。 JPA/Hibernateは

  • ない引数コンストラクタの

    いくつかのベストプラクティスは、仕様によって必要とされます。

  • コードでコードを生成しない限り、主キーのセッターは持っていません。
  • フィールドにプリミティブを使用することはできません。しかし、データベースがNOT NULLを強制する場合は、getterとsetterでprimitive longを使用する必要があります。そのため、IDEはテストが失敗するのを待つのではなく、NPEについて警告することができます。
  • リストではなく、コレクションではないリストを使用します。
  • フィールド名に下線を使用しますが、列の名前を指定するときは下線を使用します。
  • getVendors()でnullチェックとコレクションの作成に注目してください。オブジェクトの最初の作成時にNPEを回避するためです。つまり、AuditLogが作成されたばかりであっても、DBからロードされた場合でも、同じロジックを使用してAuditVendorPairを追加することができます。まれに、リスト全体を置換する必要がないかぎり、setVendors()を作成しないことを意味します。通常、リスト内のすべてのエンティティを明示的に削除する必要があります。
+0

情報ありがとうございます。 AuditLogを永続化しようとすると次のようになります。 com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 'audit_id'列をnullにできません 子parent_idから親id列に外部キー参照を追加する必要がありますか? – skeptic01

+0

コード例については、以下の回答を参照してください。 –

0

JPAの背後にある原則についてもう少し詳しくお読みください。 Springのデータを使用し、@PersistanceUnitをオートワイヤすると、エンティティマネージャ自身を管理する必要はありませんが、コードがどのように見えるのかは未処理のJPAの例です。

EntityManagerFactory emf = Persistence.createEntityManagerFactory("PU-Name"); 
EntityManager em = emf.createEntityManager(); 

try { 
    long primaryKey = 1L; // comes from somewhere else 
    long vendorId = 1L; // comes from somewhere 
    AuditLog log = em.find(AuditLog.class, primaryKey); // loaded from DB 

    AuditVendorPair pair = new AuditVendorPair(); 
    pair.setAuditLog(log); 
    pair.setVendorId(vendorId); 
    em.getTransaction().begin(); 
    em.persist(pair); 
    em.getTransaction().commit(); 
} finally { 
    em.close(); 
} 

エンティティをコードで接続し、既存のエンティティをデータベースからロードする必要があります。新しいAuditVendorPairを格納する場合は、まずAuditLogオブジェクトをロードしてから、新しく作成したAuditVendorPairにそのオブジェクトを設定する必要があります。通常、ベンダーもエンティティになるので、参照する必要もあります。

注:上記の例では、AuditLogのベンダーのコレクションにAuditVendorPairが追加されていないため、AuditLogとAuditVendorPairの双方向の関係は維持されません。リレーションを定義する列はAuditVendorPair(格納されています)にあるので、これは問題ではありません。次回AuditLogインスタンスをDBからロードすると、AuditVendorPairはベンダーコレクションの一部になるためです。ただし、永続コンテキストが閉じられた後でAuditLogを使用する場合は、双方向の関係を維持することをお勧めします。

:上記の例では、主キーを使用してリクエストを受け取ったと仮定しています。一般に、フロントエンドでは主キーを公開しないでください。システムでは、UIで公開されているすべてのエンティティに対して一意のフィールド(UUID)を生成します。

関連する問題