JPA多对多合并所有者触发器删除连接表

Posted

技术标签:

【中文标题】JPA多对多合并所有者触发器删除连接表【英文标题】:JPA many to many merge on the owner triggers delete on join table 【发布时间】:2013-02-15 14:40:50 【问题描述】:

我在 Customer 和 BusinessUnit 之间有多对多的关系:

public class Customer extends AbstractEntity 

    @JoinTable(name = "CUS_BUS_UNITS", 
            joinColumns = 
                @JoinColumn(name = "CUS_ID", referencedColumnName = "CUS_ID"),
            inverseJoinColumns = 
                @JoinColumn(name = "BUS_ID", referencedColumnName = "BUS_ID"))
    @ManyToMany
    private Collection<BusinessUnit> businessUnits;


public class BusinessUnit extends AbstractEntity 

    @ManyToMany(mappedBy = "businessUnits")
    private Collection<Customer> customers;


当我调用 entityManager.merge(customer);在一个客户(已经在数据库中,未更改)我在日志中看到这两个 sql 命令:

休眠:更新 CUSTOMERS 集 CUS_DESCR=?、CUS_NAME=?、CUS_ENABLED=? CUS_ID=?休眠:从 CUS_BUS_UNITS 中删除 CUS_ID=?

为什么休眠试图从连接表中删除一条记录? 我只需要更新客户记录和可能的连接表中的记录 - 取决于我是否添加或删除了客户的业务部门。不应更新、删除或插入业务单位。

编辑: 我的 equals/hashCode 是(在 AbstractEntity 中定义):

public int hashCode() 
    if (getId() != null) 
        return getId().hashCode();
    
    return super.hashCode();

public boolean equals(Object obj) 
    if (this == obj) 
        return true;
    
    if (obj == null) 
        return false;
    
    if (getClass() != obj.getClass()) 
        return false;
    
    AbstractEntity other = (AbstractEntity) obj;
    if (getId() == null || other.getId() == null) 
        return false;
    
    if (!getId().equals(other.getId())) 
        return false;
    
    return true;

编辑 2 表格转换器:

@FacesConverter("businessUnitConverter")
public class BusinessUnitConverter implements Converter 

    /**
     * @inheritDoc
     */
    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) 
        return ((BusinessUnit) object).getId().toString();
    


    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) 
        BusinessUnit businessUnit = new BusinessUnit();
        businessUnit.setId(Long.parseLong(value));
        return businessUnit;
    


【问题讨论】:

Customer 和 BusinessUnit 是否都有正确的 hashcode 和 equals 方法? 我为 SO 删除了它 - 但他们有抽象父级,这些方法使用实体 id 来表示 equals/hashcode。 当添加一个新的BusinessUnit 时,hibernate 会设置 id,这会改变你的 equals 实现的对象的“身份”,这可能会导致混淆。可以不使用equalshashCode 试试看问题是否仍然存在? 只有当你实现了自己的 hashcode 和 equals 方法时才会发生这种情况。所以只是为了缩小你的问题,尝试删除equals和hashcode方法,看看是否有帮助。如果这能解决问题,请告诉我们! 我试图删除这些方法,但它引起了另一个问题。所以我想这对我来说不是解决方案。用 eq/hashcode 方法更新了我的问题。 【参考方案1】:

我找到了答案:http://assarconsulting.blogspot.fr/2009/08/why-hibernate-does-delete-all-then-re.html

由于使用了 Collection,此行为是正确的(请参阅链接文章)。我使用 Set 而不是 collection,它工作正常。

【讨论】:

以上是关于JPA多对多合并所有者触发器删除连接表的主要内容,如果未能解决你的问题,请参考以下文章

mysql,SQL,触发器,多对多

仅从 Spring Data JPA 中的联接表(多对多)中选择特定列

触发器根据多对多关系插入多行

用jpa删除连接表中的行

多对多关系中的 JPA 条件查询

jpa 多对多,带有附加列和复合键