Reputation: 7229
I have two models: User
and Room
. A user belongs to many rooms and a room has many users.
Currently I have
public class User extends BasePersistable {
private static final long serialVersionUID = 1492535311821424305L;
@Column(nullable = false, unique = true)
private String login;
@Column(nullable = false)
private Integer uid;
@ManyToMany(targetEntity = Room.class)
@JoinTable(name = "room_users", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "room_id")})
private Set<Room> rooms = new HashSet<>();
and
public class Room extends AbstractAggregateRoot implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonIgnore
private Long id;
@ManyToMany(mappedBy = "rooms", targetEntity = User.class, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE})
@JsonIgnore
private Set<User> users = new HashSet<>();
when a user logs in, I either find or create him, and then I find or create rooms for him based on some rules.
for me, two things are very clear:
1) A room has many messages and messages do not exists without a room, therefore, room is a aggregate root.
2) User needs to be manipulated outside room's scope, therefore, User should also be a aggregate root.
so here comes the problem: I've learned that an aggregate root does not references another aggregate root (only through value objects). the aggregate root should contain all that it needs to exists without depend on external source (in this case, User aggregate root).
How can I create this relationship between them? and after user logs in, how can I create the rooms I need to create for him? I was thinking I could publish an event and then based on this (UserCreatedEvent
) created the rooms...am I in the right direction?
Upvotes: 4
Views: 1612
Reputation: 1582
the way I see it, a User is not in any Room. But he might have a subscription to receive all Messages published in a room. Subscriptions can be created as a mediator between users and rooms. And they can run out and therefor be deleted. The only Information they carry is the relation to the room and the user (and maybe a validity interval), they have no id because they are just this, value objects.
If you want to avoid a user referencing rooms, but are ok with a value object in between, then maybe the subscription will do the trick for you.
Upvotes: 1
Reputation: 17673
Yes, you are in the right direction.
For processes that span multiple aggregates you can use a Saga/Process manager. This component works by listening to relevant events (i.e. UserCreatedEvent
) and sends commands to the relevant aggregates. In your case, the Saga would send one or more CreateRoom
commands for every room that need to be created.
You should keep in mind that this process is eventual consistent, i.e. there is a time delay from when the event is emitted to when the commands are sent.
Upvotes: 3