web-dev-qa-db-ja.com

JPA @OneToOne with Shared ID-これをもっとうまくできますか?

私は既存のスキーマを使用していますが、変更したくないです。スキーマは、PersonテーブルとVitalStatsテーブルの間に1対1の関係があります。Personは主キーを持ち、VitalStatsはその主キーと外部キーの両方と同じフィールドをPersonに使用します。つまり、その値は対応するPKの値人の。

これらのレコードは外部プロセスによって作成され、私のJPAコードはVitalStatsを更新する必要はありません。私のオブジェクトモデルでは、PersonクラスにVitalStatsメンバーを含めたいのですが、

しようとすると

@Entity
public class Person{
    private long id;
    @Id
    public long getId(){ return id; }

    private VitalStats vs;
    @OneToOne(mappedBy = “person”)
    public VitalStats getVs() { return vs; }
}

@Entity
    public class VitalStats{
     private Person person;
    @OneToOne
    public Person getPerson() { return person; }
}

VitalStatsには@Idが欠けているという問題がありますが、@ Entityでは機能しません。\

私が試してみると

@Id @OneToOne
public Person getPerson() { return person; }

@Idの問題は解決しますが、Personをシリアライズ可能にする必要があります。それに戻ります。

VitalStatsを@Embeddableにして、@ ElementCollectionを介してPersonに接続できますが、要素が1つしかないことを知っていても、コレクションとしてアクセスする必要があります。実行可能ですが、少し迷惑で少し混乱します。

では、PersonがSerializableを実装していると言っているのを防いでいるのはなぜですか?理由はありませんが、コード内のすべてのものがそこにあることが好きで、これに対するロジックが表示されないため、コードが読みにくくなります。

それまでは、VitalStatsのPersonフィールドを長いpersonIdに置き換え、そのVitalStatsの@Idを作成したので、@ OneToOneが機能するようになりました。

(私には)単純な問題のように思われるこれらの解決策はすべて少し不格好であるため、何かが足りないのか、誰かが少なくともSerializableである理由を説明できるのかどうか疑問に思っています。

TIA

60
Michael

共有主キーを使用して1対1の関連付けをマップするには、@PrimaryKeyJoinColumnおよび@MapsId注釈を使用します。

Hibernateリファレンスドキュメントの関連セクション:

PrimaryKeyJoinColumn

PrimaryKeyJoinColumnアノテーションは、エンティティのプライマリキーが関連付けられたエンティティの外部キー値として使用されることを示しています。

MapsId

MapsIdアノテーションは、Hibernateに別の関連付けられたエンティティから識別子をコピーするように要求します。 Hibernateの専門用語では、外部ジェネレーターとして知られていますが、JPAマッピングは読みやすく、推奨されています

Person.Java

@Entity
public class Person {

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

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private VitalStats vitalStats;       
}

VitalStats.Java

@Entity
public class VitalStats 
{
    @Id @Column(name="vitalstats_id") Long id;

    @MapsId 
    @OneToOne(mappedBy = "vitalStats")
    @JoinColumn(name = "vitalstats_id")   //same name as id @Column
    private Person person;

    private String stats;
}

個人データベーステーブル

CREATE TABLE  person (
  person_id   bigint(20) NOT NULL auto_increment,
  name        varchar(255) default NULL,
  PRIMARY KEY  (`person_id`)
) 

VitalStatsデータベーステーブル

CREATE TABLE  vitalstats 
(
  vitalstats_id  bigint(20) NOT NULL,
  stats          varchar(255) default NULL,
  PRIMARY KEY  (`vitalstats_id`)
)
87
Joel Hudon

私の場合、これはトリックを作りました:

親クラス:

public class User implements Serializable {
  private static final long serialVersionUID = 1L;

  /** auto generated id (primary key) */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(unique = true, nullable = false)
  private Long id;

  /** user settings */
  @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
  private Setting setting;
}

子クラス:

public class Setting implements Serializable {
  private static final long serialVersionUID = 1L;

  /** setting id = user id */
  @Id
  @Column(unique = true, nullable = false)
  private Long id;

  /** user with this associated settings */
  @MapsId
  @OneToOne
  @JoinColumn(name = "id")
  private User user;
}
17
camposer