iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
1
Modern Web

站在Web前端人員角度,學習 Spring Boot 後端開發系列 第 26

Day 26 - Spring Boot @OneToMany X @ManyToOne 資料庫關聯

之前的實作TODO一張資料表是一張單獨的表,今天增加一個User的表,一個User可以對應到很多TODO,而TODO表和USER表有多對一的關聯,Foreign key 是 user_id。
https://ithelp.ithome.com.tw/upload/images/20201005/20118857rhniboDpoe.png

TODO TABLE

+------------+---------------+------+-----+---------+
| Field      | Type          | Null | Key | Default |
+------------+---------------+------+-----+---------+
| id         | int           | NO   | PRI |  auto   |
| task       | varchar       | YES  |     |  NULL   |
| status     | int           | NO   |     |   1     |
| create_time| TIMESTAMP     | NO   |     | current |
| update_time| TIMESTAMP     | NO   |     | current |
| user_id    | int           | YES  | FK  |  NULL   |
+------------+---------------+------+-----+---------+

USER TABLE

+------------+---------------+------+-----+---------+
| Field      | Type          | Null | Key | Default |
+------------+---------------+------+-----+---------+
| id         | int           | NO   | PRI |  auto   |
| name       | varchar       | YES  |     |  NULL   |
| gender     | int           | NO   |     |   1     |
| password   | varchar       | YES  |     |  NULL   |
+------------+---------------+------+-----+---------+

實現一對多與多對一的雙向關聯,讓USER可以參考到TODO,TODO也可以參考到USER,儲存時把主控權交給多的那方(即TODO),可以比喻成學生記老師名字比老師記同學名字快。

實作TODO與USER的雙向關聯

TODO Entity 主控方
@ManyToOne(cascade = CascadeType.ALL) 多對一

  • CascadeType.REMOVE 關聯刪除操作,當刪除當前實體時,有關係映射的實體也會被刪除
  • CascadeType.MERGE 關聯更新操作,當前實體數據改變後,有關聯的也會跟著變
  • CascadeType.REFRESH 關聯刷新操作,資料庫更新至實體
  • CascadeType.ALL 有所有關聯操作的權限
    @JoinColumn(name="user_id", referencedColumnName="id") FK 為user_id ,關聯至USER 的id
@Entity
@Table
@Data
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;

    @Column
    String task = "";

    @Column(insertable = false, columnDefinition = "int default 1")
    Integer status = 1;

    @CreatedDate
    @Column(updatable = false, nullable = false)
    Date createTime = new Date();

    @LastModifiedDate
    @Column(nullable = false)
    Date updateTime = new Date();

    @JsonBackReference
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="user_id")
    private User user;

}

USER Entity 被控方
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user") 一對多關聯至TODO entity 的user上
@EqualsAndHashCode.Exclude

@Entity
@Table
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;

    @Column
    public String name;

    @Column(insertable = false, columnDefinition = "int default 1")
    Integer gender = 1;

    @Column
    public String password;

    @JsonManagedReference
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
    @EqualsAndHashCode.Exclude
    private Set<Todo> todos;
}

@JsonManagedReference與@JsonBackReference為了解決物件中存在雙向引用導致的無限遞迴問題,在處理數據之間的雙向鏈接,一個用於父級角色,另一個用於子級角色。@JsonManagedReference被序列化的數據,而@JsonBackReference標註,不會被序列化。

再來,我們想要取得特定user的todos
(1)增加一個UserDao

public interface UserDao extends CrudRepository<User, Integer> {
}

(2)增加一個UserService

@Service
public class UserService {
    @Autowired
    UserDao userDao;

    public Optional<User> getTodosByUserId(Integer id) {
        Optional<User> data = userDao.findById(id);
        return data;
    }
}

(3)UserController 取得Todos by UserId

@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("/users/{id}/todos")
    public ResponseEntity getTodosByUserId (@PathVariable Integer id) {
        Optional<User> todos = userService.getTodosByUserId(id);
        return ResponseEntity.status(HttpStatus.OK).body(todos);
    }
}

先至http://localhost:9100/h2-console ,將資料輸入至資料庫

Insert into USER (GENDER, NAME) values (1, 'caili');

INSERT INTO TODO (TASK, STATUS, UPDATE_TIME, CREATE_TIME, USER_ID) values ('寫鐵人賽', 1, '2020-09-09 17:00', '2020-09-09 17:00', 1);

進入http://localhost:9100/api/users/1/todos 可以看到下圖
https://ithelp.ithome.com.tw/upload/images/20201005/20118857VWLi24Yty2.png


上一篇
Day 25 - Spring Boot logging 記錄記起來
下一篇
Day 27 - Spring Boot @ManyToMany多對多查詢
系列文
站在Web前端人員角度,學習 Spring Boot 後端開發30

尚未有邦友留言

立即登入留言