Set 無序 ≠ 無法有序展示。數據庫表記錄本身也是無序的,但我們通過 `ORDER BY` 實現有序查詢。Hibernate 中同理:Set 保證唯一性,排序交給查詢或視圖層處理。
// 用戶-角色:一個用戶不應有重複角色
@Entity
public class User {
@ManyToMany
@JoinTable(name = "user_role")
private Set roles = new HashSet<>(); // 業務語義:角色唯一
}
// List 可能導致:
user.getRoles().add(roleA);
user.getRoles().add(roleA); // 重複
session.save(user); // 拋出 ConstraintViolationException 或保存重複行
// Set 自動去重:
user.getRoles().add(roleA);
user.getRoles().add(roleA); // 第二次添加無效
session.save(user); // 正常,只保存一條關聯
// HQL/JPQL
SELECT u FROM User u JOIN FETCH u.roles r ORDER BY r.name ASC
// Criteria API
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(User.class);
Root root = cq.from(User.class);
root.fetch("roles", JoinType.LEFT).join("name").asc();
@ManyToMany
@JoinTable(name = "user_role")
@OrderBy("name ASC") // 數據庫層面排序
private Set roles = new LinkedHashSet<>(); // 保持插入/查詢順序
注意:`@OrderBy` 作用於數據庫查詢,配合 `LinkedHashSet` 可在內存中保持順序。
// Service/Controller
List roleDtos = user.getRoles().stream()
.map(RoleDto::from)
.sorted(Comparator.comparing(RoleDto::getName))
.collect(Collectors.toList());
❌ 「Set 無序所以不能用在頁面展示」
✅ 「Set 保證業務唯一性,展示順序由查詢 `ORDER BY` 或視圖層排序保證」
❌ 「List 更方便,直接用 List 代替 Set」
✅ 「List 需手動維護唯一性,易產生臟數據;Set 語義更清晰,性能更優」
總結:Set 的核心價值是「業務唯一性約束」與「高效查重」,順序問題通過數據庫查詢或應用層排序完美解決,這正是關注點分離的體現。