Back to course home
0% completed
Vote For New Content
CQRS Pattern: An Example
Let's consider a simple application that manages user profiles. In this application, you can create a new user (command), update their email (command), and view user details (query).
1. Command Model (Write Model)
- Command Class: Defines an action to be performed. For instance,
CreateUserCommand
with fields likeuserId
,name
, andemail
. - Command Handler: Processes the commands. It would take
CreateUserCommand
, perform business logic, and persist the changes. - Domain Model: Represents the state of the data (e.g., a
User
class). - Repository: Handles data persistence.
2. Query Model (Read Model)
- DTO (Data Transfer Object): Represents the data we want to read, like
UserProfileDTO.
- Query Class: Defines a query, for instance,
GetUserProfileQuery
with auserId
. - Query Handler: Handles the query and returns the requested data, often using a read-optimized storage.
3. Infrastructure
- Command Bus: Routes commands to their respective handlers.
- Query Bus: Routes queries to their respective handlers.
- Event Store: In a more advanced CQRS setup, this would store events resulting from commands.
Here is the sample code for the aforementioned components:
Command Model (Write Model)
1. Command Class
public class CreateUserCommand { private String userId; private String name; private String email; // Constructor, Getters, and Setters } public class UpdateUserEmailCommand { private String userId; private String newEmail; // Constructor, Getters, and Setters }
2. Command Handler
public class CreateUserCommandHandler { private UserRepository userRepository; public CreateUserCommandHandler(UserRepository userRepository) { this.userRepository = userRepository; } public void handle(CreateUserCommand command) { User user = new User(command.getUserId(), command.getName(), command.getEmail()); userRepository.save(user); } } public class UpdateUserEmailCommandHandler { private UserRepository userRepository; public UpdateUserEmailCommandHandler(UserRepository userRepository) { this.userRepository = userRepository; } public void handle(UpdateUserEmailCommand command) { if (!isValidEmail(command.getNewEmail())) { throw new IllegalArgumentException("Invalid email format"); } User user = userRepository.findById(command.getUserId()); if (user != null) { user.setEmail(command.getNewEmail()); userRepository.save(user); } } private boolean isValidEmail(String email) { // Simple email validation logic return email != null && email.contains("@"); } }
3. Domain Model
public class User { private String id; private String name; private String email; // Constructor, Getters, and Setters }
4. Repository
public interface UserRepository { void save(User user); User findById(String id); } public class UserRepositoryImpl implements UserRepository { // Implementation of save and findById methods }
Query Model (Read Model)
1. DTO (Data Transfer Object)
public class UserProfileDTO { private String id; private String name; private String email; // Constructor, Getters, and Setters }
2. Query Class
public class GetUserProfileQuery { private String userId; // Constructor, Getters, and Setters } // Read Email Query public class ReadUserEmailQuery { private String userId; // Constructor, Getters, and Setters }
3. Query Handler
public class GetUserProfileQueryHandler { private UserRepository userRepository; public GetUserProfileQueryHandler(UserRepository userRepository) { this.userRepository = userRepository; } public UserProfileDTO handle(GetUserProfileQuery query) { User user = userRepository.findById(query.getUserId()); return new UserProfileDTO(user.getId(), user.getName(), user.getEmail()); } } // Read Email Query Handler public class ReadUserEmailQueryHandler { private UserRepository userRepository; public ReadUserEmailQueryHandler(UserRepository userRepository) { this.userRepository = userRepository; } public String handle(ReadUserEmailQuery query) { User user = userRepository.findById(query.getUserId()); return user != null ? user.getEmail() : null; } }
Infrastructure
1. Command Bus
public interface CommandBus { void dispatch(CreateUserCommand command); } public class SimpleCommandBus implements CommandBus { private CreateUserCommandHandler handler; public SimpleCommandBus(CreateUserCommandHandler handler) { this.handler = handler; } @Override public void dispatch(CreateUserCommand command) { handler.handle(command); } }
2. Query Bus
public interface QueryBus { UserProfileDTO dispatch(GetUserProfileQuery query); } public class SimpleQueryBus implements QueryBus { private GetUserProfileQueryHandler handler; public SimpleQueryBus(GetUserProfileQueryHandler handler) { this.handler = handler; } @Override public UserProfileDTO dispatch(GetUserProfileQuery query) { return handler.handle(query); } }
3. Event Store (Simplified Example)
public interface EventStore { void storeEvent(UserEvent event); } public class SimpleEventStore implements EventStore { private List<UserEvent> events = new ArrayList<>(); @Override public void storeEvent(UserEvent event) { events.add(event); } }
Putting It All Together
Java
Java
. . . .
This example includes a basic implementation of a command bus, query bus, and a simplified event store. In a full-fledged application, an event store would be used for event sourcing, which is often paired with CQRS. The event store captures changes as a series of events, which can be replayed to rebuild the state of an entity.
.....
.....
.....
Like the course? Get enrolled and start learning!
Table of Contents
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible