Basics of Relational Database 1

Sungju Kim·2024년 9월 4일

Sparta_Coding_Camp_TIL

목록 보기
29/53

A relational database is a structured collection of data organized into tables, where each table consists of rows and columns. The relationships between these tables are defined using keys, allowing for efficient data retrieval and management.

Types of Relationships

1-to-1 Relationship: @OneToOne

Each record in one table is linked to exactly one record in another table, and vice versa.

Example (unidirectional)

In the Man class, the @JoinColumn(name = "partner_id") annotation on the woman field specifies that the Man table has a foreign key column named partner_id. This partner_id column references the id column in the Woman table, establishing a relationship between Man and Woman.
Man.java

@Entity
@Table(name = "man")
public class Man {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToOne
    @JoinColumn(name = "partner_id")
    private Woman woman;
}

Woman.java

@Entity
@Table(name = "woman")
public class Woman {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

If the following is added to Woman.java, we have a Bidirectional relationship in which both entities are aware of the relationship and can access each other, although there is only own entity that is the "owner" of the foreign key. When you modify the relationship (e.g., assigning a different Woman to a Man), the changes will be reflected in the database only if they are made through the owning side. The non-owning side will NOT automatically trigger an update to the database.

@OneToOne(mappedBy = "woman")
private Man man;

💡Unidirectional Relationship💡

In a unidirectional relationship, only one entity knows about the relationship. For example, in the initial code you provided, the Man class has a reference to the Woman class (@OneToOne private Woman woman;), but the Woman class does not have any reference back to the Man class. This means that while you can navigate from a Man object to its associated Woman, you cannot easily navigate from a Woman object to its associated Man.

N-to-1 Relationship: @ManyToOne

Multiple records in one table are linked to a single record in another table. Take the following example of food and users in an order management software in which a single user can order multiple dishes(food).

Example (unidirectional)

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

How to make it bidirectional

Add the following code under the User class:

@OneToMany(mappedBy = "user")
private List<Food> foodList = new ArrayList<>();

💡Who gets to the foreign key(FK) owner?💡

The foreign key belongs to the class with the 'Many' attribute in the 'Many to one'. This is because the "many" class would require identification for each object regarding its relationship with the "one" class. For example, if we had post and comments class where one or more comments can belong to a single post, from each comment we need to know which post it is mapped to. While the other way is also possible (identifying post is associated which comment), you cannot put a list of comments in the data table (although you can do it in the actual class). Therefore, the FK belongs to the "many" class.

1-to-N Relationship:@OneToMany

A single record in one table is linked to multiple records in another table. Let's look at this again with the Food and User class where the foreign key owning entity is the 'Many' in 'OneToMany'.

Example (unidirectional)

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToMany
    @JoinColumn(name = "food_id") // users 테이블에 food_id 컬럼
    private List<User> userList = new ArrayList<>();
}
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

Example (bidirectional, though uncommon)

Although a bidirectional relationship is uncommon for this relationship, we can set it up by modifying the User class as below:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

	@ManyToOne
	@JoinColumn(name = "food_id", insertable = false, updatable = false)
	private Food food;
}

N-to-N Relationship: @ManyToMany

Multiple records in one table are linked to multiple records in another table, typically managed through a junction table like below.

Relavent Code

Food

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToMany(mappedBy = "food")
    private List<Order> orderList = new ArrayList<>();
}

Users

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "user")
    private List<Order> orderList = new ArrayList<>();
}

Orders

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

💡 What about using the @ManyToMany annotation? -> Not recommened for the following reasons💡
When you use the @ManyToMany annotation in JPA, it automatically creates a junction table behind the scenes to manage the relationship between the two entities. This junction table contains the foreign keys from both entities but typically doesn't allow for any additional fields or customization unless explicitly defined. However, this automatic junction table is very basic, typically consisting of only the two foreign keys, and lacks flexibility for adding extra attributes (like timestamps, relationship status, or other metadata) or for customizing queries and cascade operations.

  • Explicit control over the relationship: Junction tables give more flexibility, allowing better control over cascade operations and query performance.
  • Performance and complexity: Explicit junction tables can be optimized for better performance in large applications, whereas @ManyToMany can result in inefficient queries.
  • Handling complex relationships: Junction tables can manage more complex requirements like filtering, sorting, or manipulating relationships.
  • Better control over cascade operations: Junction tables provide finer control over persistence and deletion compared to @ManyToMany.
  • Normalization best practices: Using junction tables aligns with database normalization principles, reducing redundancy and improving integrity.

@ManyToMany Annotation

Unidirectional

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @ManyToMany
    @JoinTable(name = "orders", // 중간 테이블 생성
    joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
    inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
    private List<User> userList = new ArrayList<>();
}
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

Bidirectional

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @ManyToMany
    @JoinTable(name = "orders", // 중간 테이블 생성
    joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
    inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
    private List<User> userList = new ArrayList<>();
}
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToMany(mappedBy = "userList")
    private List<Food> foodList = new ArrayList<>();
}
profile
Fully ✨committed✨ developer, always eager to learn!

0개의 댓글