領先一步
VMware 提供培訓和認證,以加速您的進展。
瞭解更多這是關於在使用 Spring Data JDBC 時可能遇到的各種挑戰的系列文章中的第二篇。本系列包含:
Spring Data JDBC - 如何建立雙向關係?(本文)。
如果您是 Spring Data JDBC 的新手,您應該先閱讀它的介紹和這篇文章,其中解釋了聚合在 Spring Data JDBC 上下文中的關聯性。相信我,這很重要。
本文基於我在 Spring One 2021 上所做的演講的一部分。
Spring Data JDBC 沒有對雙向關係的特殊支援。要理解為什麼您真的不需要任何特殊支援,我們必須查看兩種不同類型的關係:我們區分聚合內部的參考和跨聚合的參考。
讓我們先看看聚合內部的參考。這些參考在 Spring Data JDBC 中由實際的 Java 參考建模。這些參考總是從聚合根指向聚合內部的實體。實際上,參考是從更接近聚合根的實體指向更內部的實體。但同樣的論點也適用,所以我們只考慮聚合根和一個內部實體。
如果您遵循 DDD 的想法和規則,您永遠不會直接存取內部實體。相反,每當您想操作內部實體時,您都會在聚合根上呼叫一個方法,然後聚合根會在內部實體上呼叫適當的方法。如果該方法需要對聚合根的參考,您只需在呼叫內部實體上的方法時將其傳遞即可。對於中間實體也是如此。
但也許您有很多這樣的方法,並且不想到處傳遞 this
。在這種情況下,您只需在建構聚合期間而不是在方法呼叫期間傳遞參考。只是普通的 Java 程式碼,沒有任何特殊之處。
舉例來說,考慮一個 Minion
和它的 Toy
,玩具應該有一個返回到 Minion
的參考,以便它可以告訴它的主人的名字。Minion
將自己設定為其所有玩具的主人。
class Minion {
@Id
Long id;
String name;
final Set<Toy> toys = new HashSet<>();
Minion(String name) {
this.name = name;
}
@PersistenceConstructor
private Minion(Long id, String name, Collection<Toy> toys) {
this.id = id;
this.name = name;
toys.forEach(this::addToy);
}
public void addToy(Toy toy) {
toys.add(toy);
toy.minion = this;
}
public void showYourToys() {
toys.forEach(Toy::sayHello);
}
}
class Toy {
String name;
@Transient // org.SPRINGframework.DATA...
Minion minion;
Toy(String name) {
this.name = name;
}
public void sayHello() {
System.out.println("I'm " + name + " and I'm a toy of " + minion.name);
}
}
請注意,您需要使用 Spring Data 註解而不是 JPA 註解將這些反向參考設為 @Transient
。否則 Spring Data JDBC 會嘗試持久化它們,這將導致無限迴圈。
對於聚合之間的參考,情況甚至更簡單。這些參考不是透過 Java 參考實作,而是透過使用被參考聚合的 ID,可選擇包裝在 AggregateReference
中。
導覽這樣的參考會轉化為使用目標聚合的 repository 及其 findById
方法。例如,Minion
可能參考它的邪惡主人 Person
。
class Minion {
@Id
Long id;
String name;
AggregateReference<Person, Long> evilMaster;
Minion(String name, AggregateReference<Person, Long> evilMaster) {
this.name = name;
this.evilMaster = evilMaster;
}
}
class Person {
@Id
Long id;
String name;
Person(String name) {
this.name = name;
}
}
給定一個 Minion
,您現在可以載入它的邪惡主人。
@Autowired
PersonRepository persons;
//...
Minion minion = //...
Optional<Person> evilMaster = persons.findById(minion.evilMaster.getId());
為了在相反的方向導覽關係,您可以在 MinionRepository
中宣告一個方法,該方法為給定的邪惡主人尋找適當的 minions。
interface MinionRepository extends CrudRepository<Minion, Long> {
@Query("SELECT * FROM MINION WHERE EVIL_MASTER = :id")
Collection<Minion> findByEvilMaster(Long id);
}
@Autowired
MinionRepository minions;
//...
Person evilMaster = // ...
Collection<Minion>findByEvilMaster(evilMaster.id);
使用 Spring Data JDBC 2.3,您不必再使用 @Query
註解,因為查詢衍生支援 AggregateReference
作為引數類型。
雖然 Spring Data JDBC 沒有對雙向關係的明確支援,但事實證明您不需要特殊支援。您只需要現有的功能和標準 Java 程式碼。完整的範例程式碼可在 Spring Data Example repository 中找到。這裡有一個內部參考的範例和一個外部參考的範例。
未來還會有更多類似的文章。如果您希望我涵蓋特定主題,請告訴我。