You could use a join table to avoid the categories aggregating the roots like this:
@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...
}
Just as an example I'll plug a few together:
for (int n = 0; n < 3; ++n) {
categoryRepository.save(new Category());
}
Set<Category> categories = categoryRepository.findAll();
productRepository.save(new Product(categories));
Which results in the following (you didn't specify your DBMS, so I just assumed...) 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)
And of course no surprise with respect to their content:
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)
Also I would avoid storing relations in a comma-separated list when you're using a relational database. It leads to unhealthy database design and will cause you headaches at some point.
cascade = CascadeType.ALL
is heading in the wrong direction, because that ties the two aggregates to the same transaction – Granado