https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates
https://velog.io/@bongf/codesquad-lecture-210427-banchan-2-2-jdbc
class PurchaseOrder {
private @Id Long id;
private String shippingAddress;
private Set<OrderItem> items = new HashSet<>();
void addItem(int quantity, String product) {
items.add(createOrderItem(quantity, product));
}
private OrderItem createOrderItem(int quantity, String product) {
OrderItem item = new OrderItem();
item.product = product;
item.quantity = quantity;
return item;
}
}
class OrderItem {
int quantity;
String product;
}
interface OrderRepository extends CrudRepository<PurchaseOrder, Long> {
@Query("select count(*) from order_item")
int countItems();
}
Also, if you delete the PurchaseOrder, all its items should get deleted as well. Again, that’s the way it is.
…
repository.delete(saved);
assertThat(repository.count()).isEqualTo(0);
assertThat(repository.countItems()).isEqualTo(0);
}
class Book {
// …
Set<Author> authors = new HashSet<>();
}
When a Book goes out of print, you delete it. And gone are all the Authors. Certainly not what you intended, since some of the Authors probably wrote other books as well. Now, this doesn’t make sense. Or does it? I think it does.
An aggregate is a cluster of objects that form a unit, which should always be consistent. Also, it should always get persisted (and loaded) together. It has a single object, called the aggregate root, which is the only thing allowed to touch or reference the internals of the aggregate. The aggregate root is what gets passed to the repository in order to persist the aggregate.
This brings up the question: How does Spring Data JDBC determine what is part of the aggregate and what isn’t? The answer is very simple: Everything you can reach from an aggregate root by following non-transient references is part of the aggregate.
With this in mind, the behavior of the OrderRepository makes perfect sense. OrderItem instances are part of the aggregate and, therefore, get deleted. Author instances, conversely, are not part of the Book aggregate and, therefore, should not get deleted. So they should simply not get referenced from the Book class.
If multiple aggregates reference the same entity, that entity can’t be part of those aggregates referencing it since it only can be part of exactly one aggregate. Therefore any Many-to-One and Many-to-Many relationship must be modeled by just referencing the id.
여러 개의 aggregates가 하나의 entity를 참조할 때 그 entity는 그 어그리케이트들의 part가 될 수 없다.
many to one과 many to many관계는 id로 참조해야 한다.
이 문서에 나온 예시 (many-to-many)
Purchase_Order (
id
shipping_address
)
Order_Item (
purchase_order
quantity
product
);
Book (
id
title
)
Author (
id
name
)
Book_Author (
book
author
)
AuthorRef라는 새로운 클래스를 만든다. 이는 Author의 id를 갖도록 한다. 그리고 이 Book을 AuthorRef를 Set으로 갖는다.
그리고 Book이 AuthorRef를 생성하는 메소드를 private으로 갖는다. addAuthor을 하면 AuthorRef를 생성해서 이를 set으로 갖는 방식
그러면 아래와 같이 사용된다.
@Test
public void booksAndAuthors() {
Author author = new Author();
author.name = "Greg L. Turnquist";
author = authors.save(author);
Book book = new Book();
book.title = "Spring Boot";
book.addAuthor(author);
books.save(book);
books.deleteAll();
assertThat(authors.count()).isEqualTo(1);
}
To wrap it up: Spring Data JDBC does not support many-to-one or many-to-many relationships. In order to model these, use IDs.