之前的實作TODO一張資料表是一張單獨的表,今天增加一個User的表,一個User可以對應到很多TODO,而TODO表和USER表有多對一的關聯,Foreign key 是 user_id。
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 Entity 主控方
@ManyToOne(cascade = CascadeType.ALL) 多對一
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
可以看到下圖