Repository đặt một lớp trung gian giữa domain và tầng lưu trữ: domain làm việc với một tập object trong bộ nhớ, còn chuyện SQL/ORM nằm sau interface.
interface OrderRepository {
findById(id: string): Promise<Order | null>
findPendingOlderThan(d: Date): Promise<Order[]>
save(order: Order): Promise<void>
}Nó giải quyết được:
- Truy vấn nghiệp vụ có tên rõ ràng, dùng lại được, thay vì mỗi service tự nối điều kiện where riêng.
- Service test được với repository giả, không cần DB thật.
- Chi tiết lưu trữ (bảng, join, cache) đổi mà service không đổi.
Khi nó là thừa:
- Repository chỉ ủy quyền một-một cho ORM (findById gọi đúng db.order.findUnique). Lúc đó lớp này chỉ thêm file, không thêm giá trị — nhiều ORM đã là một dạng repository rồi.
- Nhóm lý luận "để đổi database sau này": việc đổi DB hiếm khi xảy ra, và khi xảy ra thì repository ít khi đủ để che vì transaction, phân trang, kiểu dữ liệu vẫn rò ra.
- Ứng dụng CRUD nhỏ, service chỉ gọi truy vấn tầm thường.
Cách dùng cân bằng: tạo repository cho aggregate có quy tắc nghiệp vụ và truy vấn lặp lại; các chỗ đọc đơn giản, đặc biệt truy vấn phục vụ hiển thị, cứ gọi thẳng query.