Hibernate EntityManager:如何删除关联

Hibernate EntityManager:如何删除关联,hibernate,many-to-many,associations,entitymanager,Hibernate,Many To Many,Associations,Entitymanager,o为了更好地理解,需要进行一些惯用的澄清:capa表示层,mapa表示映射 o一个图层可能用于不同的地图,并且一个地图可能包含许多不同的图层 o删除图层时,与贴图的关联必须消失,但贴图本身仍然存在 o相反,删除地图时,与图层的关联必须消失,但图层本身仍然存在 o映射代码: @Entity @Table(name = "CAPA") public class Capa implements Serializable { @ManyToMany(fetch=FetchType.LAZ

o为了更好地理解,需要进行一些惯用的澄清:capa表示,mapa表示映射

o一个图层可能用于不同的地图,并且一个地图可能包含许多不同的图层

o删除图层时,与贴图的关联必须消失,但贴图本身仍然存在

o相反,删除地图时,与图层的关联必须消失,但图层本身仍然存在

o映射代码:

@Entity
@Table(name = "CAPA")
public class Capa implements Serializable {    
    @ManyToMany(fetch=FetchType.LAZY, mappedBy="capas")
    private Set<Mapa> mapas;
}
@实体
@表(name=“CAPA”)
公共类Capa实现可序列化{
@ManyToMany(fetch=FetchType.LAZY,mappedBy=“capas”)
私有集映射;
}

@实体
@表(name=“MAPA”)
公共类Mapa实现了可序列化{
@ManyToMany(fetch=FetchType.LAZY)
@JoinTable(name=“mapa_capa”,joinColumns={@JoinColumn(name=“idMapa”)},inverseJoinColumns={@JoinColumn(name=“idCapa”)})
私有集capas;
}
o要删除图层(capa)及其贴图(mapas)之间的链接,我尝试了以下操作:

Capa c = findCapa();
Iterator<Mapa> itms = c.getMapas().iterator();        
while (itms.hasNext()) {
    Mapa m = itms.next(); 
    m.getCapas().remove(c);
    c.getMapas().remove(m);
    getEntityManager().refresh(m);                
    getEntityManager().refresh(c);   
}
Capa c=findCapa();
迭代器itms=c.getMapas().Iterator();
while(itms.hasNext()){
Mapa m=itms.next();
m、 getCapas()。删除(c);
c、 getMapas().remove(m);
getEntityManager().refresh(m);
getEntityManager()。刷新(c);
}
这是行不通的。两组(m.capas和c.mapas)保持不变


感谢您的帮助。

您需要调用flush以使更改在数据库中生效。您没有调用flush,而是调用refresh,因此数据库副本将覆盖您的更改。您的Capa
c
是一个对象。如果您在
Capa
类中正确地实现了
hashCode
equals
,则持久性提供程序只能知道
c
实际上存在于
Mapa
集中。否则,可能会有这样一种情况,hibernate永远不会知道
c
实际上存在于
m
中,因此
m.getCapas().remove(c)
永远不会从
m
中实际删除
c
。您可以通过计算remove调用返回的值来检查这一点。我很确定它将是
假的

这里要做的更好的事情是检查对象的主键,然后从集合中删除
实际对象

Capa c = findCapa();
Iterator<Mapa> itms = c.getMapas().iterator();        
while (itms.hasNext()) {
    Mapa m = itms.next();
    foreach(Capa c1 : m.getCapas()) {
      if(c1.getId().equals(c.getId())) {
        m.getCapas().remove(c1);
      }
    }
    //No need to remove m from c as Mapa is the owning side
    getEntityManager().refresh(m);                
    getEntityManager().refresh(c);   
}
Capa c=findCapa();
迭代器itms=c.getMapas().Iterator();
while(itms.hasNext()){
Mapa m=itms.next();
foreach(capac1:m.getCapas()){
如果(c1.getId().equals(c.getId())){
m、 getCapas()。移除(c1);
}
}
//不需要从c中删除m,因为Mapa是拥有方
getEntityManager().refresh(m);
getEntityManager()。刷新(c);
}
然而,这有一个额外的for循环


最好的做法是在所有实体中实现
equals
hashCode
方法。

感谢您的回答,它不起作用。实际上,在我发布代码之前,我已经用flush处理过了。你有没有查看日志来检查sql是否触发到数据库中?您可以使用HiberNet日志或hibernate show_sql或sql profiler进行此操作。
Capa c = findCapa();
Iterator<Mapa> itms = c.getMapas().iterator();        
while (itms.hasNext()) {
    Mapa m = itms.next();
    foreach(Capa c1 : m.getCapas()) {
      if(c1.getId().equals(c.getId())) {
        m.getCapas().remove(c1);
      }
    }
    //No need to remove m from c as Mapa is the owning side
    getEntityManager().refresh(m);                
    getEntityManager().refresh(c);   
}