【问题标题】:Hibernate5 update only collection many to many relationshipHibernate5更新只收集多对多关系
【发布时间】:2017-09-17 07:06:33
【问题描述】:

我用 Hibernate 5.2 映射了下图

这些是我的实体类:

库存

@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

}

类别

@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

}

一切正常。

我需要做的只是将类别列表添加到股票中。我不想修改Stock 实体,只是在stock_category 表中添加或删除类别。

这是我的服务:

@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();
}

这是对服务的测试

@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);
    }
}

测试运行良好,没有错误,但是在浏览与类别“13”(getAllStockeByCategoriesCriteria)关联的股票时,它没有给我带来任何股票。那么之前执行的操作就不起作用了。

如何添加或删除类别?

【问题讨论】:

  • 应该可以。请发布getAllStockeByCategoriesCriteria 实现并解释您如何在测试中管理事务(可能未提交更改)?

标签: java hibernate jpa orm jpa-2.0


【解决方案1】:

你必须在两边添加依赖,所以你错过了将Stock添加到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();
}

另外我认为你应该使用merge 而不是update 来使级联工作。

之后,您的代码应该保存关系。

【讨论】:

  • 感谢您的回答,但是必须遍历整个类别列表并添加库存会影响应用程序的性能吗?
  • 它是一个内存操作。与实际物理保存链接表相同的次数相比,它不应该那么明显。
  • 但是,例如,如果我只需要添加或删除一个类别,我就必须获取整个列表并通过它来添加或删除新对象?
【解决方案2】:

根据第一个响应,这是我在方法中留下的代码。

更改签名,因为我只需要实体的标识符就可以关联它们,并且如 Maciej Kowalski 所示,关系必须保持双向

我还通过 Set 更改了列表,以确保不会重复这些值

这将是我为关系添加类别列表的服务

@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();
}

这将是从关系中删除类别列表的服务

@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();
}

我的疑问是,在建立两个实体之间的关系之前,我必须在数据库中查询它们以获取对象并对其进行操作。因此,我必须为要关联的每个标识符都这样做,我想应该存在性能问题。

但是暂时我会留下它,以防我找到更优化的方法在这里发布它

【讨论】:

    猜你喜欢
    • 2017-01-30
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    相关资源
    最近更新 更多