2017-09-24 248 views
2

我有兩種模式:UserRoom。一個用戶屬於很多房間,而一個房間有很多用戶。
目前我有模型ddd上的多對多關係

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<>(); 

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<>(); 
當用戶登錄

,我要麼尋找或創造了他,然後我找到或創建基於某些規則的房間給他。
對我來說,兩件事情非常清楚:
1)房間裏有很多消息,消息沒有房間就不存在,因此房間是一個聚合根。
2)用戶需要在房間的範圍之外操作,因此,用戶也應該是一個聚合根。

所以問題來了:我知道一個聚合根不會引用另一個聚合根(只能通過值對象)。聚合根應該包含所有它需要存在而不依賴於外部源(在這種情況下,用戶聚合根)的情況。

如何在它們之間創建這種關係?並且在用戶登錄後,如何創建我需要爲他創建的房間?我想我可以發佈一個活動,然後基於此(UserCreatedEvent)創建了房間......我是否朝着正確的方向發展?

回答

2

是的,你是在正確的方向。

對於跨越多個集合的進程,您可以使用Saga/Process manager。該組件通過收聽相關事件(即UserCreatedEvent)工作並向相關聚合發送命令。在你的情況下,佐賀會發送一個或多個CreateRoom命令爲每個需要創建的房間。

您應該記住,這個過程是最終一致的,即從發生事件到發送命令有一段時間延遲。

1

我看到它的方式,用戶不在任何房間。但他可能會收到訂閱,收到房間內發佈的所有消息。訂閱可以創建爲用戶和房間之間的中介。他們可以用完,因此可以刪除。他們攜帶的唯一信息是與房間和用戶的關係(也可能是一個有效期間),他們沒有身份證,因爲他們就是這個價值對象。

如果您想避免用戶引用房間,但可以使用中間的值對象,那麼訂閱可能會爲您解決問題。

+0

這是一個非常好的方式來把它...我會睡在上面,看看我能做些什麼!但有一個問題:如果他們沒有身份證,我該如何建立這種關係...我的意思是,我肯定需要保存這些信息... –

+1

你應該看看@ElementCollection。如果這對你不起作用(或者你的eclipse jpa插件導致你的整個Project充滿錯誤),你仍然可以將它建模爲JPA實體。僅僅因爲某些技術標識將其存儲在數據庫中並不意味着它在您的域中有一個id。 ...你可以讓id字段爲private,而不是將setter/getter -methods添加到id。 – EasterBunnyBugSmasher