1

私は次の2つのエンティティを持っています:

Person.java:

@Entity
@Table(name="PERSON")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id")
    private int id;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "person", optional = false)
    private Address address;

    public Person(final String firstName, final String lastName, final Address address)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    //Required by hibernate
    public Person()
    {
    }

    public int getId()
    {
        return id;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public Address getAddress() {
        return address;
    }

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

    public void setFirstName(final String firstName)
    {
        this.firstName = firstName;
    }

    public void setLastName(final String lastName)
    {
        this.lastName = lastName;
    }

    public void setAddress(final Address address)
    {
        this.address = address;
    }

}

Address.java:

@Entity
@Table(name = "ADDRESS")
public class Address
{
    @Id
    private int personId;

    @MapsId
    @OneToOne()
    private Person person;

    @Column(name = "street")
    private String street;

    @Column(name = "town")
    private String town;

    @Column(name = "postcode")
    private String postcode;

    public Address()
    {
    }

    public Address(final String street, final String town, final String postcode)
    {
        this.street = street;
        this.town = town;
        this.postcode = postcode;
    }

    public Person getPerson()
    {
        return person;
    }

    public void setPerson(final Person person)
    {
        this.person = person;
        this.personId = person.getId();
    }

    public String getStreet()
    {
        return street;
    }

    public void setStreet(final String street)
    {
        this.street = street;
    }

    public String getTown()
    {
        return town;
    }

    public void setTown(final String town)
    {
        this.town = town;
    }

    public String getPostcode()
    {
        return postcode;
    }

    public void setPostcode(final String postcode)
    {
        this.postcode = postcode;
    }

}

これらの2つのエンティティを次のスキーマにマップしたいと思います。

CREATE TABLE person (
    id INT NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(50) NULL DEFAULT NULL,
    last_name VARCHAR(50) NULL DEFAULT NULL,
    PRIMARY KEY (id)
);
CREATE TABLE address (
    person_id INT(10) NOT NULL,
    street VARCHAR(50) NULL DEFAULT NULL,
    town VARCHAR(50) NULL DEFAULT NULL,
    postcode VARCHAR(50) NULL DEFAULT NULL,
    FOREIGN KEY (person_id) REFERENCES person(id) ON DELETE CASCADE
);

アドレステーブルには主キーがなく、個人テーブルへの外部キーのみがあることに注意してください。これは、アドレスに関連付けられた人がいなければアドレスは存在できず、マッピングは1対1でなければならないことを意味します。

残念ながら、Hibernateアノテーションは正しく機能しません。これは私が上記をテストするために使用しているコードです:

public static Person save(Person person) {
    SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
    Session session = sf.openSession();
    session.beginTransaction();
    Integer id = (Integer)session.save(person);
    person.setId(id);
    session.getTransaction().commit();
    session.close();
    return person;
}

@Test
public void testWritePerson() {
    Person person = new Person("Jack", "Bauer", new Address("123 Fake Street", "Springfield", "SP1F 123"));
    person.getAddress().setPerson(person);

    Person savedPerson = PersonTestUtil.save(person);
    assertFalse(
}

しかし、私が得るエラーは次のとおりです。

org.hibernate.id.IdentifierGenerationException: null id generated for:class Address

私はさまざまな異なる注釈の多くの順列を試しましたが、成功しませんでした。上記のコードの注釈を修正して、PersonエンティティとAddressエンティティの両方を正しく保持する方法はありますか?自分でテストしたい場合の完全なコードは、データベースのセットアップ方法の説明とともにここにあります。

https://github.com/alexspurling/hibernate-test

4

3 に答える 3

2

解決策は、アドレス フィールドの Person の OneToOne 注釈から "optional = false" 属性を削除することであることがわかりました。

@OneToOne(cascade = CascadeType.ALL, mappedBy = "person")
private Address address;

Person の ID が生成される前に Hibernate が Address を保持しようとするのを防ぐため、これはうまくいくと思います。

完全な動作例については、更新された github リポジトリをご覧ください: https://github.com/alexspurling/hibernate-test

于 2012-11-19T13:32:01.900 に答える
0

マッピングを変更してみてください(他は問題ありません)。これを読む

http://viralpatel.net/blogs/hibernate-one-to-one-mapping-tutorial-using-annotation/

人は大丈夫です

アドレスはこのように変更する必要があります

public class Address {

  @Id
  @Column(name="personId", unique=true, nullable=false)
  @GeneratedValue(generator="gen")
  @GenericGenerator(name="gen", strategy="foreign"
           , parameters=@Parameter(name="property", value="person"))
  private int personId;

  @OneToOne
  @PrimaryKeyJoinColumn
  private Person person
  ...

新しい値を挿入するときに、両端を明示的に設定できます。

于 2012-11-17T06:37:27.743 に答える
0

Address オブジェクトの personID フィールドは、person オブジェクト属性の状態を反映する必要があると思います。アドレス エンティティに次の変更を加えてみてください。

public void setPerson(final Person person)
{
    this.person = person;
    this.personId = person.getId();
}

一方を設定するときは、他方が同期されていることを確認する必要があります。

編集
わかりました、私の提案がうまくいかないことがわかりました。基本的な問題は、Address の ID を Person の Id で設定する必要があることですが、Person ID は持続時に自動生成されるため、その値はまだありません。Id on Address には、実際には Person への外部キーであることを JPA に伝える注釈がないため、生成された person Id でこれを設定することを認識できません。
あなたがする必要があるのは、JPA に十分な情報を提供して、Person を保存し、その Id を使用して Address を保存することを認識させることです。私はこのようなことを試してみます。

@Entity
@Table(name = "ADDRESS")
public class Address
{
    //*** Use the Person object to get and set this value
    //*** @Id
    //*** private int personId;

    @Id
    @OneToOne()
    private Person person;

これで、JPA には、オブジェクトを保存する順序と Address に personId を設定する方法を理解するのに十分な注釈付き情報が必要です。
最後に、テスト ケースの Address に Person を設定した行は、必須のステップであるため、Person コンストラクターに移動する必要があります。この行がないと、JPA には 2 つをリンクできるオブジェクト参照がありません。

public Person(final String firstName, final String lastName, final Address address)
{
     this.firstName = firstName;
     this.lastName = lastName;
     this.address = address;
     this.address.setPerson(this);
} 

そうすべきだと思います。

于 2012-11-16T15:06:43.427 に答える