2016-12-26 4 views
4

DDD 원칙을 따르면 하나의 집계 루트는 다른 집계 루트에 대한 참조 (ID 별) 만 가져야합니다.DDD : JPA/Hibernate 엔티티 관계로 올바르게 구현하는 방법?

예 :

// Product Aggregate root 
class Product { 

    // References to categories Aggregate Roots (to ids) 
    Set<Long> categoryIds; 
} 

그러나이 JPA 달성 할 수있는 방법/최대 절전 모드? 우리가하려는 경우 는 JPA에서, 예를 들어, OneToMany 관계, 우리는 다음과 같이 정의 :

// Product Aggregate root 
class Product { 

    // Holds category aggregate roots 
    @OneToMany(mappedBy = "", cascade = CascadeType.ALL) 
    Set<Category> categories; 
} 

그래서 JPA-의 접근 방식 DDD 권장되지 않는, 카테고리 집계 뿌리 자체를 개최한다.

어떻게 JPA와의 관계를 설계하겠습니까? 그러나 DDD 원칙에 맞습니까?

추신 : 나는 categories 문자열 유형의 속성을 생각하고 쉼표로 구분 된 범주 ID 목록을 보유하고 있지만 더 좋은 해결책이 있습니까?

@Entity 
public class Product { 

    @Id 
    @GeneratedValue 
    private int id; 

    @OneToMany 
    @JoinTable 
    private Set<Category> categories; 

    // constructor, getters, setters, etc... 
} 


@Entity 
public class Category { 
    @Id 
    @GeneratedValue 
    private int id; 

    // constructor, getters, setters, etc... 
} 

그냥 예를 들어 내가 몇 함께 연결합니다 :

+0

'캐스케이드 = CascadeType.ALL'가 잘못된 방향으로 향하고있다 그 두 집계를 동일한 트랜잭션에 연결합니다. –

답변

1

당신은 종류가 같은 뿌리를 집계 방지하기 위해 테이블을 조인을 사용할 수있는 결과

for (int n = 0; n < 3; ++n) { 
    categoryRepository.save(new Category()); 
} 

Set<Category> categories = categoryRepository.findAll(); 

productRepository.save(new Product(categories)); 

다음 (당신은 DBMS를 지정하지 않았기 때문에 나는 단지 ...) MySQL :

MariaDB [so41336455]> show tables; 
+----------------------+ 
| Tables_in_so41336455 | 
+----------------------+ 
| category    | 
| product    | 
| product_categories | 
+----------------------+ 
3 rows in set (0.00 sec) 

MariaDB [so41336455]> describe category; describe product; describe product_categories; 
+-------+---------+------+-----+---------+----------------+ 
| Field | Type | Null | Key | Default | Extra   | 
+-------+---------+------+-----+---------+----------------+ 
| id | int(11) | NO | PRI | NULL | auto_increment | 
+-------+---------+------+-----+---------+----------------+ 
1 row in set (0.00 sec) 

+-------+---------+------+-----+---------+----------------+ 
| Field | Type | Null | Key | Default | Extra   | 
+-------+---------+------+-----+---------+----------------+ 
| id | int(11) | NO | PRI | NULL | auto_increment | 
+-------+---------+------+-----+---------+----------------+ 
1 row in set (0.00 sec) 

+---------------+---------+------+-----+---------+-------+ 
| Field   | Type | Null | Key | Default | Extra | 
+---------------+---------+------+-----+---------+-------+ 
| product_id | int(11) | NO | PRI | NULL |  | 
| categories_id | int(11) | NO | PRI | NULL |  | 
+---------------+---------+------+-----+---------+-------+ 
2 rows in set (0.00 sec) 

MariaDB [so41336455]> select * from category; select * from product; select * from product_categories; 
+----+ 
| id | 
+----+ 
| 1 | 
| 2 | 
| 3 | 
+----+ 
3 rows in set (0.00 sec) 

+----+ 
| id | 
+----+ 
| 1 | 
+----+ 
1 row in set (0.00 sec) 

+------------+---------------+ 
| product_id | categories_id | 
+------------+---------------+ 
|   1 |    1 | 
|   1 |    2 | 
|   1 |    3 | 
+------------+---------------+ 
3 rows in set (0.00 sec) 

은 또한 당신이 관계형 데이터베이스를 사용하는 경우 쉼표로 구분 된 목록에서 관계를 저장 피할 것 : 자신의 콘텐츠에 대한 놀라운 일을 SE는 없습니다. 그것은 건강에 해로운 데이터베이스 디자인으로 이어지고 어느 시점에서 두통을 일으킬 것입니다.

+0

그러나 다시, 'Product'는'Category'의 집합을 가지고 있습니다. 이것이 DDD에 따라 우리가 처음부터 피해야 만하는 것입니다. –

+0

예, 'Category'는이 경우 CategoryId가되어야합니다. – Teimuraz

0

집계 사이를 이동할 때 ID로 참조하는 것이 가장 좋습니다. 집계 동작을 호출하기 전에 서비스를 사용하여 필요한 개체를로드하십시오. 예를 들면 :

public class MyProductApplicationService { 
    ... 
    @Transactional 
    public void loadDependentDataAndCarryOutAggregateAction(Long productId, Long categoryId) { 

     Product product = productRepository.findOne(productId); 
     Category category = categoryRepository.findOne(categoryId); 

     product.doActionThatNeedsFullCategoryAndMayModifyProduct(category); 
    } 
} 

그 후 적어도 하나 개의 집합에서 다른 트랜잭션에 걸쳐하지 않는, 너무 복잡 경우, 때문에

class Product { 

    @OneToMany(mappedBy = "product") 
    Set<Category> categories; 
} 

public class Category { 

    @ManyToOne 
    @JoinColumn(name = "productid", insertable = false, updatable = false) 
    private Product product; 
} 
+0

고맙습니다.하지만 첫 번째 방법에서는 제품에 대한 카테고리 참조를 어디에 저장할 것입니까? – Teimuraz

+0

@moreo'@Column private long productId'를'Category'에 추가하면됩니다. –