5.1 さまざまな形式の 1 対 1 コミュニケーション

2 つのエンティティ クラス間の関係、つまり 1 対 1 の関係に関する興味深い、かなり具体的なケースがもう 1 つあります。

これはデータベースというよりも Java オブジェクトに関するものであるため、私はこのケースを非常に特殊なケースと呼んでいます。データベースでは、テーブル間の関係には次の 2 つのオプションしかありません。

  • テーブルの行には、別のテーブルの ID へのリンクが含まれています。
  • サービス テーブルは多対多の関係に使用されます。

エンティティ クラスの場合、いくつかのアノテーションによって記述されるオプションが存在する場合があります。

  • @埋め込み
  • 一方的なOneToOne
  • 二者間OneToOne
  • @MapsId

以下では、それらの中で最も人気のあるものを検討します。

5.2 埋め込み型

ところで、私たちはすでに最も単純な1 対 1 の@Embedded通信オプションを検討しました - これは 注釈 です。この場合、データベース内の同じテーブルに 2 つのクラスが格納されています。

ユーザーのアドレスをUserAddressクラスに保存したいとします。


@Embeddable
class UserAddress {
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
}

次に、このアドレスを持つフィールドをUserクラスに追加するだけです。


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

残りの作業は Hibernate が行います。データは 1 つのテーブルに保存されますが、HQL クエリを作成するときはクラス フィールドを操作する必要があります。

HQL クエリの例:

select from User where address.city = 'Paris'

5.3 一方的なOneToOne

ここで、ソース テーブルの従業員と従業員を参照するタスクがある状況を想像してください。ただし、1 人のユーザーに割り当てられるタスクは最大 1 つであることは確かです。次に、注釈を使用してこの状況を説明できます@OneToOne

例:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @OneToOne
   @JoinColumn(name = "employee_id")
   public Employee employee;
 
   @Column(name="deadline")
   public Date deadline;
}

Hibernate は、1 つのタスクに 1 人のユーザーが存在するだけでなく、1 人のユーザーが 1 つのタスクだけを持つことも確認します。それ以外の場合、このケースは と実質的に変わりません@ManyToOne

5.4 二国間 OneToOne

従業員をタスクに割り当てるだけでなく、従業員にタスクを割り当てることも必要になることが多いため、前のオプションは少し不便な場合があります。

これを行うには、EmployeeTask フィールドを Employee クラスに追加し、それに正しい注釈を付けます。


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
   private EmployeeTask task;
}

重要!従業員テーブルにはtask_idフィールドがありません。代わりに、テーブル間の関係を確立するためにタスクテーブルの従業員 IDフィールドが使用されます。

オブジェクト間の接続の確立は次のようになります。


Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
 
session.update(task);
session.flush();

リンクを削除するには、両方のオブジェクトからもリンクを削除する必要があります。


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
 
task.employee = null;
session.update(task);
 
director.task = null;
session.update(director);
 
session.flush();