Jpa one-to-one, one-to-many did not understand the words, always feel a little round, today let’s have a brief talk about this topic.

1. One to one

For example, a school has one address, and an address has only one school.

So we can design the class as follows:

@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;
}
Copy the code

One-to-one relationships can be maintained only in School, only in Address, or both, depending on the requirements.

In the example above, we maintain a one-to-one relationship with the @onetoone annotation in both School and Address.

Cascade Is used to configure the cascade operation. The value can be:

  • ALL: indicates ALL operations
  • PERSIST: cascades the interface to be added
  • MERGE: Cascading updates
  • REMOVE: indicates cascading deletion
  • REFRESH: Cascades REFRESH

Just choose the right one for your needs.

T_school = address_AID = school_SID = school_SID = school_sid = school_SID = school_SID

For those who are not comfortable with the automatic addition of this field, you can also customize the field. The field will always be present anyway. You can customize it as follows:

@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;
}
Copy the code

Add a sid to Address and make it unmodifiable. Use the @JoinColumn annotation to specify the name of the attribute in the current class. ReferencedColumnName represents the corresponding attribute name in the School class.

Do something similar in the School class.

Finally, start the project to observe the tables generated in MySQL.

2. One to many

There are multiple students in a class, and a student belongs to only one class, we can define the entity class like this:

@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;
}
Copy the code

Student and Clazz are many-to-one annotated with @manytoone, while Clazz and Student are one-to-many annotated with @onetomany.

Student and Clazz have a many-to-one relationship. In the future, the t_student table will have a foreign key clazz_cid to associate Student with Clazz. If we don’t want an autogenerated clazz_CID, we can customize it as follows:

@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;
}
Copy the code

Define a CID attribute and make it uneditable and unadditive, then configure the CID attribute as a foreign key using the @JoinColumn annotation.

The relationship between Clazz and Student is one-to-many, and this is achieved by an automatically generated third table, as follows:

3. The test

3.1 Adding tests

Let’s start with a one-to-one add test like this:

public interface SchoolRepository extends JpaRepository<School.Integer> {}@SpringBootTest
class JpaOneToManyApplicationTests {

    @Autowired
    SchoolRepository schoolRepository;
    @Test
    void contextLoads(a) {
        School school = new School();
        school.setSid(1);
        school.setName("Harvard University");
        Address address = new Address();
        address.setAid(1);
        address.setProvince("Heilongjiang");
        address.setCity("Harbin");
        address.setArea("Somewhere");
        address.setPhone("123456"); school.setAddress(address); schoolRepository.save(school); }}Copy the code

In this test, the relationship is maintained by the T_school side, so the foreign key that will be populated will be the AID in T_school. The result is as follows:

This is a simple addition case.

Update is also called save method, the update will first determine whether the ID exists, if it does not exist, update, add.

Let’s look at the addition of classes as follows:

public interface ClazzRepository extends JpaRepository<Clazz.Integer> {}@Autowired
ClazzRepository clazzRepository;
@Test
void test02(a) {
    Clazz c = new Clazz();
    c.setCid(1);
    c.setName("Class Two, Grade Three");
    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("Zhang");
    students.add(s2);
    c.setStudents(students);
    clazzRepository.save(c);
}
Copy the code

Note that the class is added, so the relationship between the class and the student is maintained by the third table, not by the student.

3.2 Query Tests

To do another simple query, suppose we now want to search for schools by province, as follows:

public interface SchoolRepository extends JpaRepository<School.Integer> {
    List<School> findSchoolByAddressProvince(String province);
}
@Autowired
SchoolRepository schoolRepository;
@Test
void test01(a) {
    List<School> list = schoolRepository.findSchoolByAddressProvince("Heilongjiang");
    System.out.println("list = " + list);
}
Copy the code

Here’s how Spring Data interprets the above custom query methods:

  1. First intercept findSchoolByAddressProvince prefix, AddressProvince left.
  2. Check whether the School has the addressProvince attribute. If so, query according to this attribute. For our case, there is no addressProvince attribute, so proceed to the next step.
  3. Start from the right hump and remove the content behind the first hump. In this case, only Address is left after the split. Determine whether the Address attribute exists in School, if not, continue to repeat the step and continue to cut the first hump on the right.
  4. In the example above, the School has the address attribute, so we need to check whether the address attribute is present in the School, because we only have one province left. If the remaining string looks like provinceAaaBbb, So continue with step 3.

There is a small risk that if the School has a property called addressProvince, the analysis will be wrong. So, for the above query, we can also define as follows:

public interface SchoolRepository extends JpaRepository<School.Integer> {
    List<School> findSchoolByAddress_Province(String province);
}
Copy the code

There is no ambiguity, and the system knows that province is a property of address.

Let’s do another class query as follows:

public interface ClazzRepository extends JpaRepository<Clazz.Integer> {}@Test
void test03(a) {
    List<Clazz> list = clazzRepository.findAll();
    System.out.println("list = " + list);
}
Copy the code

If you need to sort students during the query, add the following attributes:

@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;
}
Copy the code

The student sort of the query can be set by @orderby (“sid desc”).

Well, a few small cases, I hope to help you, the public account back jPA02, to obtain the download link of this case.