Reputation: 1210
I have the following diagram mapped with Hibernate 5.2
These are my entity classes:
Stock
@Entity
@Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = {
@UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STOCK_ID", unique = true, nullable = false)
private Integer stockId;
@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
private String stockCode;
@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
private String stockName;
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.REFRESH})
@JoinTable(name = "stock_category", catalog = "mkyongdb", joinColumns = {
@JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) },
inverseJoinColumns = { @JoinColumn(name = "CATEGORY_ID",
nullable = false, updatable = false) })
private Set<Category> categories = new HashSet<>();
//Getter and Setter
}
Category
@Entity
@Table(name = "category", catalog = "mkyongdb")
public class Category implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "CATEGORY_ID", unique = true, nullable = false)
private Integer categoryId;
@Column(name = "NAME", nullable = false, length = 10)
private String name;
@Column(name = "[DESC]", nullable = false)
private String desc;
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories", cascade = {CascadeType.MERGE, CascadeType.REFRESH})
private Set<Stock> stocks = new HashSet<>();
//Getter and Setter
}
Everything works well.
What I need to do is just add a category listing to a stock. I do not want to modify the Stock
entity, just add or remove categories from the stock_category
table.
This is my service:
@Override
@Transactional(rollbackFor = StockException.class)
public void addCategoriesToStock(Set<Category> categories, Stock stock) throws StockException{
stock = sessionFactory.getCurrentSession().get(Stock.class, stock.getCodStock());
stock.setCategories(categories);
sessionFactory.getCurrentSession().update(stock);
sessionFactory.getCurrentSession().flush();
}
This is the test for the service
@Test
public void testAddCategoriesStock() throws Exception {
Stock newValues = new Stock();
newValues.setStockId(1);
Category category = new Category();
category.setCategoryId(13);
dao.addCategoriesToStock(new HashSet<>(Arrays.asList(category)), newValues);
List<Stock> stocks = dao.getAllStockeByCategoriesCriteria(category);
for (Stock stock : stocks) {
System.out.println(stock);
}
}
The test runs well without errors, but when browsing the stock associated with category "13" (getAllStockeByCategoriesCriteria
), it does not bring me any stock. Then the previously executed operation did not work.
What can I do to add or remove categories?
Upvotes: 4
Views: 218
Reputation: 1210
Based on the first response this is the code I leave in the method.
Change the signature because I only need the identifiers of the entities to be able to relate them and as indicated Maciej Kowalski the relationship must stay both ways
I also changed the lists by Set to make sure the values were not going to be duplicated
This would be my service to add a list of categories to the relationship
@Override
@Transactional(rollbackFor = StockException.class)
public void addCategoriesToStock(Set<Integer> categoryCodes, Integer codStock) throws StockException{
//I get the stock I'm going to associate
Stock stock = sessionFactory.getCurrentSession().get(Stock.class, codStock);
if (categoryCodes != null) {
//For each category to add to the stock, I consult and add the relationship in both entities
for (Integer codCategory : categoryCodes) {
Category category = sessionFactory.getCurrentSession().get(Category.class, codCategory);
category.add(stock);
stock.add(category);
}
}
sessionFactory.getCurrentSession().merge(stock);
sessionFactory.getCurrentSession().flush();
}
This would be the service to remove a list of categories from the relationship
@Override
@Transactional(rollbackFor = StockException.class)
public void removeCategoriesToStock(Set<Integer> categoryCodes, Integer codStock) throws StockException{
//I get the stock that I will disassociate
Stock stock = sessionFactory.getCurrentSession().get(Stock.class, codStock);
if (categoryCodes != null) {
//For each category to eliminate the stock, I consult and eliminate the relationship in both entities
for (Integer codCategory : categoryCodes) {
Category category = sessionFactory.getCurrentSession().get(Category.class, codCategory);
category.remove(stock);
stock.remove(category);
}
}
sessionFactory.getCurrentSession().merge(stock);
sessionFactory.getCurrentSession().flush();
}
The doubt I have is that before I can make the relationship between both entities I have to consult them in the database to get the object and manipulate it. As this I have to do it for each identifier that I will associate there should be a performance problem I suppose.
But for the moment I'll leave it in case I find a more optimal way to do so post it here
Upvotes: 0
Reputation: 26502
You have to add the dependencies on both sides, so you are missing the addition of Stock to categories
:
@Override
@Transactional(rollbackFor = StockException.class)
public void addCategoriesToStock(List<Category> categories, Stock stock) throws StockException{
stock = sessionFactory.getCurrentSession().get(Stock.class, stock.getCodStock());
stock.setCategories(categories);
for(Category cat: categories){
cat.getStocks().add(stock);
}
sessionFactory.getCurrentSession().merge(stock);
sessionFactory.getCurrentSession().flush();
}
Also i think you should use merge
instead of update
for the cascade to work.
After that your code should save the relationships.
Upvotes: 1