Theo tôi hiểu, ý tưởng lớn đằng sau CQRS là có 2 mô hình dữ liệu khác nhau để xử lý các lệnh và truy vấn. Chúng được gọi là "mô hình viết" và "mô hình đọc".
Hãy xem xét một ví dụ về bản sao ứng dụng Twitter. Dưới đây là các lệnh:
- Người dùng có thể tự đăng ký.
CreateUserCommand(string username)
phát raUserCreatedEvent
- Người dùng có thể theo dõi người dùng khác.
FollowUserCommand(int userAId, int userBId)
phát raUserFollowedEvent
- Người dùng có thể tạo bài viết.
CreatePostCommand(int userId, string text)
phát raPostCreatedEvent
Trong khi tôi sử dụng thuật ngữ "sự kiện" ở trên, tôi không có nghĩa là các sự kiện 'tìm nguồn cung ứng sự kiện'. Tôi chỉ có nghĩa là tín hiệu kích hoạt đọc cập nhật mô hình. Tôi không có cửa hàng sự kiện và cho đến nay muốn tập trung vào chính CQRS.
Và đây là các truy vấn:
- Một người dùng cần phải xem danh sách các bài viết của nó.
GetPostsQuery(int userId)
- Một người dùng cần phải xem danh sách những người theo dõi nó.
GetFollowersQuery(int userId)
- Một người dùng cần phải xem danh sách người dùng mà nó theo dõi.
GetFollowedUsersQuery(int userId)
- Người dùng cần xem "nguồn cấp dữ liệu bạn bè" - nhật ký của tất cả các hoạt động của bạn bè họ ("bạn của bạn John vừa tạo một bài đăng mới").
GetFriedFeedRecordsQuery(int userId)
Để xử lý CreateUserCommand
tôi cần biết nếu một người dùng như vậy đã tồn tại. Vì vậy, tại thời điểm này tôi biết rằng mô hình viết của tôi nên có một danh sách tất cả người dùng.
Để xử lý FollowUserCommand
tôi cần biết nếu userA đã theo dõi userB hay chưa. Tại thời điểm này, tôi muốn mô hình viết của mình có một danh sách tất cả các kết nối người dùng theo dõi người dùng.
Và cuối cùng, để xử lý CreatePostCommand
tôi không nghĩ mình cần gì nữa, vì tôi không có lệnh như thế nào UpdatePostCommand
. Nếu tôi có những thứ đó, tôi sẽ cần đảm bảo rằng bài đăng đó tồn tại, vì vậy tôi sẽ cần một danh sách tất cả các bài viết. Nhưng vì tôi không có yêu cầu này, tôi không cần phải theo dõi tất cả các bài viết.
Câu hỏi số 1 : có thực sự đúng khi sử dụng thuật ngữ "mô hình viết" theo cách tôi sử dụng không? Hay "mô hình viết" luôn luôn thay thế cho "cửa hàng sự kiện" trong trường hợp ES? Nếu vậy, có bất kỳ loại tách giữa dữ liệu tôi cần để xử lý các lệnh và dữ liệu tôi cần để xử lý các truy vấn không?
Để xử lý GetPostsQuery
, tôi sẽ cần một danh sách tất cả các bài viết. Điều này có nghĩa là mô hình đọc của tôi nên có một danh sách tất cả các bài viết. Tôi sẽ duy trì mô hình này bằng cách lắng nghe PostCreatedEvent
.
Để xử lý cả hai GetFollowersQuery
và GetFollowedUsersQuery
, tôi sẽ cần một danh sách tất cả các kết nối giữa những người dùng. Để duy trì mô hình này, tôi sẽ lắng nghe UserFollowedEvent
. Đây là câu hỏi số 2 : thực tế có ổn không nếu tôi sử dụng danh sách kết nối của mô hình ghi ở đây? Hoặc tốt hơn tôi nên tạo một mô hình đọc riêng biệt, bởi vì trong tương lai tôi có thể cần nó để có nhiều chi tiết hơn mô hình viết?
Cuối cùng, để xử lý GetFriendFeedRecordsQuery
tôi sẽ cần:
- Nghe
UserFollowedEvent
- Nghe
PostCreatedEvent
- Biết người dùng nào theo dõi người dùng khác
Nếu người dùng A theo dõi người dùng B và người dùng B bắt đầu theo dõi người dùng C, các bản ghi sau sẽ xuất hiện:
- Đối với người dùng A: "Bạn bè người dùng B vừa bắt đầu theo dõi người dùng C"
- Đối với người dùng B: "Bạn vừa mới bắt đầu theo dõi người dùng C"
- Đối với người dùng C: "Người dùng B hiện đang theo dõi bạn"
Đây là Câu hỏi số 3 : Tôi nên sử dụng mô hình nào để có danh sách các kết nối? Có nên sử dụng mô hình viết? Tôi có nên sử dụng mô hình đọc - GetFollowersQuery
/ GetFollowedUsersQuery
? Hoặc tôi nên làm cho GetFriendFeedRecordsQuery
mô hình tự xử lý UserFollowedEvent
và duy trì danh sách tất cả các kết nối của riêng mình?