2024. 5. 30. 09:38ㆍBack-End
Java Persistence API (JPA)는 객체 관계 매핑(ORM) 기술을 통해 객체 지향 프로그래밍 언어의 객체를 관계형 데이터베이스의 테이블에 매핑한다. JPA에서는 다양한 엔티티 간의 관계를 정의할 수 있다. 본 글에서는 JPA에서의 @OneToMany, @ManyToOne, @OneToOne, @ManyToMany에 대해 설명하고, 각각의 관계에서 데이터를 저장, 수정, 삭제하는 예시를 다룰 것이다. 또한 JPA의 상속 매핑 전략에 대해서도 자세히 살펴보자.
엔티티 간의 관계
@OneToMany와 @ManyToOne
@OneToMany와 @ManyToOne 관계는 가장 흔히 사용되는 관계 중 하나로, 하나의 엔티티가 여러 엔티티와 관계를 맺는 경우이다.
예시: 국가와 도시의 관계
- Country: 여러 City를 가질 수 있다.
- City: 하나의 Country에 속할 수 있다.
@Entity
public class Country {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "country", cascade = CascadeType.ALL, orphanRemoval = true)
private List<City> cities = new ArrayList<>();
// Getter, Setter, Constructor
}
@Entity
public class City {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "country_id")
private Country country;
// Getter, Setter, Constructor
}
데이터 저장, 수정, 삭제 예시
public void saveCountryAndCities(EntityManager em) {
em.getTransaction().begin();
Country country = new Country();
country.setName("USA");
City city1 = new City();
city1.setName("New York");
city1.setCountry(country);
City city2 = new City();
city2.setName("Los Angeles");
city2.setCountry(country);
country.getCities().add(city1);
country.getCities().add(city2);
em.persist(country);
em.getTransaction().commit();
}
public void updateCity(EntityManager em, Long cityId) {
em.getTransaction().begin();
City city = em.find(City.class, cityId);
if (city != null) {
city.setName("San Francisco");
}
em.getTransaction().commit();
}
public void deleteCountry(EntityManager em, Long countryId) {
em.getTransaction().begin();
Country country = em.find(Country.class, countryId);
if (country != null) {
em.remove(country);
}
em.getTransaction().commit();
}
@OneToOne
@OneToOne 관계는 하나의 엔티티가 다른 하나의 엔티티와 1:1로 연결되는 경우이다.
예시: 사용자와 프로필의 관계
- User: 하나의 Profile을 가질 수 있다.
- Profile: 하나의 User에 속할 수 있다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "profile_id")
private Profile profile;
// Getter, Setter, Constructor
}
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
// Getter, Setter, Constructor
}
데이터 저장, 수정, 삭제 예시
public void saveUserAndProfile(EntityManager em) {
em.getTransaction().begin();
User user = new User();
user.setUsername("johndoe");
Profile profile = new Profile();
profile.setBio("Software Developer");
user.setProfile(profile);
em.persist(user);
em.getTransaction().commit();
}
public void updateProfile(EntityManager em, Long profileId) {
em.getTransaction().begin();
Profile profile = em.find(Profile.class, profileId);
if (profile != null) {
profile.setBio("Senior Software Developer");
}
em.getTransaction().commit();
}
public void deleteUser(EntityManager em, Long userId) {
em.getTransaction().begin();
User user = em.find(User.class, userId);
if (user != null) {
em.remove(user);
}
em.getTransaction().commit();
}
@ManyToMany
@ManyToMany 관계는 여러 엔티티가 서로 다수와 연결될 수 있는 경우이다.
예시: 학생과 수업의 관계
- Student: 여러 Course를 수강할 수 있다.
- Course: 여러 Student가 수강할 수 있다.
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
// Getter, Setter, Constructor
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
// Getter, Setter, Constructor
}
데이터 저장, 수정, 삭제 예시
public void saveStudentAndCourses(EntityManager em) {
em.getTransaction().begin();
Student student = new Student();
student.setName("Alice");
Course course1 = new Course();
course1.setTitle("Mathematics");
Course course2 = new Course();
course2.setTitle("Physics");
student.getCourses().add(course1);
student.getCourses().add(course2);
course1.getStudents().add(student);
course2.getStudents().add(student);
em.persist(student);
em.getTransaction().commit();
}
public void updateCourseTitle(EntityManager em, Long courseId) {
em.getTransaction().begin();
Course course = em.find(Course.class, courseId);
if (course != null) {
course.setTitle("Advanced Mathematics");
}
em.getTransaction().commit();
}
public void deleteStudent(EntityManager em, Long studentId) {
em.getTransaction().begin();
Student student = em.find(Student.class, studentId);
if (student != null) {
em.remove(student);
}
em.getTransaction().commit();
}
엔티티 상속
JPA는 엔티티 간의 상속 관계를 정의할 수 있다. 주요 상속 전략으로는 SINGLE_TABLE, JOINED, TABLE_PER_CLASS가 있다.
SINGLE_TABLE 전략
모든 엔티티를 하나의 테이블에 저장하고, 구분 컬럼을 사용하여 각 엔티티 유형을 식별하는 전략이다.
예시
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getter, Setter, Constructor
}
@Entity
@DiscriminatorValue("MGR")
public class Manager extends Employee {
private String department;
// Getter, Setter, Constructor
}
@Entity
@DiscriminatorValue("ENG")
public class Engineer extends Employee {
private String specialty;
// Getter, Setter, Constructor
}
JOINED 전략
각 엔티티를 별도의 테이블에 저장하고, 기본 키를 사용하여 상속 계층 구조를 연결하는 전략이다.
예시
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getter, Setter, Constructor
}
@Entity
public class Manager extends Employee {
private String department;
// Getter, Setter, Constructor
}
@Entity
public class Engineer extends Employee {
private String specialty;
// Getter, Setter, Constructor
}
TABLE_PER_CLASS 전략
각 엔티티를 별도의 테이블에 저장하고, 각 테이블이 상속된 모든 속성을 가지는 전략이다.
예시
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
// Getter, Setter, Constructor
}
@Entity
public class Manager extends Employee {
private String department;
// Getter, Setter, Constructor
}
@Entity
public class Engineer extends Employee {
private String specialty;
// Getter, Setter, Constructor
}
데이터 저장, 수정, 삭제 예시
public void saveEmployeeAndManager(EntityManager em) {
em.getTransaction().begin();
Employee employee = new Employee();
employee.setName("John Smith");
Manager manager = new Manager();
manager.setName("Jane Doe");
manager.setDepartment("HR");
em.persist(employee);
em.persist(manager);
em.getTransaction().commit();
}
public void updateManagerDepartment(EntityManager em, Long managerId) {
em.getTransaction().begin();
Manager manager = em.find(Manager.class, managerId);
if (manager != null) {
manager.setDepartment("Finance");
}
em.getTransaction().commit();
}
public void deleteEmployee(EntityManager em, Long employeeId) {
em.getTransaction().begin();
Employee employee = em.find(Employee.class, employeeId);
if (employee != null) {
em.remove(employee);
}
em.getTransaction().commit();
}
결론
JPA는 엔티티 간의 다양한 관계를 정의하고 관리할 수 있는 강력한 기능을 제공한다. @OneToMany, @ManyToOne, @OneToOne, @ManyToMany를 통해 데이터베이스 모델을 객체 지향적으로 표현할 수 있다. 또한, 상속 매핑 전략(SINGLE_TABLE, JOINED, TABLE_PER_CLASS)을 통해 엔티티 간의 상속 관계를 효과적으로 구현할 수 있다.
'Back-End' 카테고리의 다른 글
kafka (0) | 2024.08.04 |
---|---|
[AWS] EC2와 RDS 설정 및 프로젝트 배포 (0) | 2024.06.12 |
로깅(SLF4J) (0) | 2024.05.30 |
JPA와 ORM (0) | 2024.05.30 |