2016-12-26 15 views
4

DDDの原則に従えば、1つの集約ルートは、別の集約ルートへの参照(IDによる)のみを持つ必要があります。DDD:JPA/Hibernateエンティティの関係で正しく実装する方法は?

例:

// Product Aggregate root 
class Product { 

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

しかし、どのようにJPAを/ Hibernateでそれを達成することができますか?私たちは、例えば、OneToMany関係を持つようにしたい場合は、JPAで は、我々は次のようにそれを定義した:

// Product Aggregate root 
class Product { 

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

をだから、JPA-のアプローチはDDDで推奨されていないカテゴリ集計根自体を、開催します。

JPAとの関係はどのように設計するのですか?ただし、DDDの原則に適合するにはどうすればよいですか?

P .:私は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'があるため、間違った方向に向かっています2つの集約を同じトランザクションに結びつけます –

答えて

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) 

その内容に関しては何の驚きをSEん:

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) 

また、私はあなたがリレーショナルデータベースを使用している際に、カンマ区切りのリストで関係を格納避けるだろう。これは、データベースの設計が不健全になり、ある時点で頭痛を引き起こします。

+0

もう一度、 'Product'は' Category'のセットを保持します。 DDDによれば、まずそれを避けるべきです。 –

+0

はい、この場合の「カテゴリ」はカテゴリIDだけです – Teimuraz

0

アグリゲート間をナビゲートするときは、アイデンティティを参照することをお勧めします。集計動作を呼び出す前に、サービスを使用して必要なオブジェクトをロードします。たとえば、次のように

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'に追加するだけです –

関連する問題