Jpaで1対1と1対多を理解していないと、いつも少し混乱するでしょう。今日は、このトピックについて簡単に説明しましょう。
1.1対1
たとえば、学校には1つの住所があり、住所には1つの学校しかありません。
次に、次のようにクラスを設計できます。
@Data
@Entity
@Table(name = "t_address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String province;
private String city;
private String area;
private String phone;
@OneToOne(cascade = CascadeType.ALL)
private School school;
}
@Data
@Entity
@Table(name = "t_school")
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@OneToOne(cascade = CascadeType.ALL)
private Address address;
}
1対1の関係は、要件に応じて、学校のみ、住所のみ、またはその両方で維持できます。
上記の例では、@ OneToOneアノテーションを使用して、学校と住所の両方で1対1の関係を維持しています。
カスケードは、次の値でカスケード操作を構成するために使用されます。
- ALL:すべての操作
- PERSIST:カスケード追加
- マージ:カスケード更新
- 削除:カスケード削除
- 更新:カスケード更新
必要に応じて適切なものを選択してください。
このようにして、最終的に作成されるt_schoolテーブルとt_addressテーブルには、それぞれ追加のフィールドaddress_aidとschool_sidがあります。これら2つのフィールドは外部キーであり、2つのテーブルの異なるレコードが関連付けられるのは外部キーを介して行われます。 。
この自動的に追加されたフィールドに慣れていない人もいるので、フィールドをカスタマイズすることもできます。とにかく、フィールドは常に必須です。カスタマイズ方法は次のとおりです。
@Data
@Entity
@Table(name = "t_address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String province;
private String city;
private String area;
private String phone;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "sid",referencedColumnName = "sid")
private School school;
@Column(insertable = false,updatable = false)
private Integer sid;
}
@Data
@Entity
@Table(name = "t_school")
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "aid",referencedColumnName = "aid")
private Address address;
@Column(insertable = false,updatable = false)
private Integer aid;
}
Addressのsidをカスタマイズし、フィールドを追加または変更しないように設定してから、@ JoinColumnアノテーションを使用して関係を指定します。@JoinColumnアノテーションの名前は現在のクラスのプロパティ名を表し、referencedColumnNameは学校を表します。クラス。に対応する属性名。
学校のクラスでも同じようなことをします。
最後にプロジェクトを開始して、MySQLで生成されたテーブルを観察します。
2.1対多
クラスには複数の学生がいて、学生は1つのクラスにのみ属しているため、エンティティクラスを次のように定義できます。
@Data
@Table(name = "t_student")
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
private Clazz clazz;
}
@Data
@Table(name = "t_clazz")
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer cid;
private String name;
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Student> students;
}
StudentとClazzの関係は、@ ManyToOneで注釈が付けられた多対多であり、ClazzとStudentの関係は、@OneToManyで注釈が付けられた1対多です。
StudentとClazzの関係は多対1です。将来的には、t_studentテーブルに追加の属性clazz_cidが追加され、この外部キーを介してStudentとClazzが関連付けられます。自動生成されたclazz_cidが必要ない場合は、次のようにカスタマイズすることもできます。
@Data
@Table(name = "t_student")
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "cid")
private Clazz clazz;
@Column(insertable = false,updatable = false)
private Integer cid;
}
cidプロパティを定義し、編集不可および追加不可として設定してから、@JoinColumnアノテーションを使用してcidプロパティを外部キーとして構成します。
ClazzとStudentの関係は1対多であり、次のように、自動生成された3番目のテーブルを介して実現されます。
3.テスト
3.1テストを追加
まず、次のように1対1のテストを追加しましょう。
public interface SchoolRepository extends JpaRepository<School,Integer> {
}
@SpringBootTest
class JpaOneToManyApplicationTests {
@Autowired
SchoolRepository schoolRepository;
@Test
void contextLoads() {
School school = new School();
school.setSid(1);
school.setName("哈佛大学");
Address address = new Address();
address.setAid(1);
address.setProvince("黑龙江");
address.setCity("哈尔滨");
address.setArea("某地");
address.setPhone("123456");
school.setAddress(address);
schoolRepository.save(school);
}
}
このテストプロセスでは、関連付け関係はt_school側によって維持されるため、将来入力される外部キーはt_schoolの援助です。追加の結果は次のとおりです。
これは単純な加算の場合です。
更新では、saveメソッドも呼び出されます。更新時には、最初にIDが存在するかどうかが判別されます。存在する場合は更新され、存在しない場合は追加されます。
次のように、クラスの追加を見てみましょう。
public interface ClazzRepository extends JpaRepository<Clazz,Integer> {
}
@Autowired
ClazzRepository clazzRepository;
@Test
void test02() {
Clazz c = new Clazz();
c.setCid(1);
c.setName("三年级二班");
List<Student> students = new ArrayList<>();
Student s1 = new Student();
s1.setSid(1);
s1.setName("javaboy");
students.add(s1);
Student s2 = new Student();
s2.setSid(2);
s2.setName("张三");
students.add(s2);
c.setStudents(students);
clazzRepository.save(c);
}
クラスが追加されるため、クラスと生徒の関係は、生徒ではなく3番目のテーブルによって維持されることに注意してください。
3.2クエリテスト
別の簡単なクエリ次のように、州ごとに学校を検索するとします。
public interface SchoolRepository extends JpaRepository<School,Integer> {
List<School> findSchoolByAddressProvince(String province);
}
@Autowired
SchoolRepository schoolRepository;
@Test
void test01() {
List<School> list = schoolRepository.findSchoolByAddressProvince("黑龙江");
System.out.println("list = " + list);
}
Song Geは、SpringDataが上記のカスタムクエリメソッドをどのように解析するかを示します。
- まず、findSchoolByAddressProvinceのプレフィックスを切り捨てて、AddressProvinceを残します。
- 学校にaddressProvince属性があるかどうかを確認し、この属性に従ってクエリを実行します。この場合、addressProvince属性がないため、次の手順に進みます。
- 右側のこぶから分割を開始し、最初のこぶの背後にあるコンテンツを削除します。分割後、アドレスのみが残ります。学校にアドレス属性があるかどうかを確認します。存在しない場合は、この手順を繰り返して、切り取りを続けます。最初のAハンプ。
- 上記の場合、Schoolに住所属性があるので、ここに残っている州は1つだけなので、住所にプロビジョニング属性があるかどうかを確認しましょう。残りの文字列がProvinceAaaBbbに類似している場合は、3番目の手順に進みます。分析することです。
上記の書き方にはリスクが少ないですが、学校にaddressProvinceという物件があると、現時点での分析は間違っています。したがって、上記のクエリでは、次のように定義することもできます。
public interface SchoolRepository extends JpaRepository<School,Integer> {
List<School> findSchoolByAddress_Province(String province);
}
この時点で、あいまいさはなくなり、システムは州が住所の属性であることを認識します。
次のような別のクラスクエリ:
public interface ClazzRepository extends JpaRepository<Clazz,Integer> {
}
@Test
void test03() {
List<Clazz> list = clazzRepository.findAll();
System.out.println("list = " + list);
}
クエリ中に生徒を並べ替える必要がある場合は、次の属性を追加できます。
@Data
@Table(name = "t_clazz")
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer cid;
private String name;
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@OrderBy("sid desc")
private List<Student> students;
}
@OrderBy( "sid desc")を使用して、クエリの学生の順序を設定できます。
さて、いくつかの小さなケースですが、皆さんのお役に立てば幸いです。パブリックアカウントのバックグラウンドでjpa02に返信し、このケースのダウンロードリンクを入手してください。