Java 休眠继承实体的多对多联接表不持久

Java 休眠继承实体的多对多联接表不持久,java,hibernate,inheritance,hibernate-annotations,Java,Hibernate,Inheritance,Hibernate Annotations,我已经阅读了关于多对多关系的文章,并尝试遵循他们的建议,但我的解决方案没有成功。希望有人能对这个话题有所启发 我有一个数据库结构,试图通过Hibernate映射多对多关系。我的想法是,我有许多实体可能相互冲突。就表结构而言,这些实体中的每一个都是相似的,因此我将它们从一个常见的持久化类中抽象出来,AbstractEntity。由于实体可能存在冲突,并且可能与任何数量的其他实体存在冲突,因此我定义了一个单独的冲突Hibernate实体来定义每个冲突,它应该通过多对多关系映射到冲突中的每个实体 以下

我已经阅读了关于多对多关系的文章,并尝试遵循他们的建议,但我的解决方案没有成功。希望有人能对这个话题有所启发

我有一个数据库结构,试图通过Hibernate映射多对多关系。我的想法是,我有许多实体可能相互冲突。就表结构而言,这些实体中的每一个都是相似的,因此我将它们从一个常见的持久化类中抽象出来,
AbstractEntity
。由于实体可能存在冲突,并且可能与任何数量的其他实体存在冲突,因此我定义了一个单独的
冲突
Hibernate实体来定义每个冲突,它应该通过多对多关系映射到冲突中的每个实体

以下是实体声明。我将
事件
作为
抽象实体
对象的具体实现示例

我的类和Hibernate配置:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractEntity {
    protected Set<Conflict> conflicts = null;

    protected AbstractEntity() {
        conflicts = new HashSet<Conflict>();
    }

    @ManyToMany(fetch = FetchType.LAZY,
            targetEntity = Conflict.class)
    @JoinTable(name = "conflict_affected_entity",
            joinColumns = { @JoinColumn(name = "affected_entity_id") }, 
            inverseJoinColumns = { @JoinColumn(name = "conflict_id") })
    public Set<Conflict> getConflicts() {
        Hibernate.initialize(conflicts);
        return conflicts;
    }

    public void setConflicts(Set<Conflict> conflicts) {
        this.conflicts.clear();
        this.conflicts.addAll(conflicts);
    }
}

@Entity
@Table(name = "event")
public class Event extends AbstractEntity {

    private String name;

    public Event() {
        super();
    }

    @Column(name = "name", nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String text) {
        this.name = text;
    }
}

@Entity
@Table(name = "conflict")
public class Conflict {

    private Set<AbstractEntity> affectedEntities = null;

    public Conflict() {
        affectedEntities = new HashSet<AbstractEntity>();
    }

    @ManyToMany(fetch = FetchType.LAZY,
            targetEntity = AbstractEntity.class,
            mappedBy = "conflicts")
    public Set<AbstractEntity> getAffectedEntities() {
        Hibernate.initialize(affectedEntities);
        return affectedEntities;
    }

    public void setAffectedEntities(Set<AbstractEntity> affectedEntities) {
        this.affectedEntities.clear();
        this.affectedEntities.addAll(affectedEntities);
    }
}

Hibernate似乎对发生的事情有所了解,所以我觉得我错过了一些简单的事情。当我创建一个新的
冲突
,并向其中添加一个
抽象实体
时,将创建冲突和抽象实体,但联接表仍然为空。有人能给我一个提示,让我做什么让Hibernate填充空白的连接表吗?< /P> < P>你的表有主键吗?< /P> 将@ManyToMany映射更改为:

@JoinTable(name = "conflict_affected_entity",
        joinColumns = { @JoinColumn(name = "affected_entity_id", referencedColumnName="primaryKeyOfAffectedEntityColumnName") }, 
        inverseJoinColumns = { @JoinColumn(name = "conflict_id", referencedColumnName="primaryKeyOfConflictColumnName") })

根据您显示的代码,包括如何保存数据,问题在于哪个实体拥有关系。在代码中,您已经在AbstractEntity类中映射了@ManyToMany,这意味着AbstractEntity及其子类是拥有关系的类,并且负责连接表的数据库更新。在冲突类中,您已经正确定义了多对多关系,并且使用

mappedBy = "conflicts"
您已经告诉Hibernate,多对多关系的第二个定义实际上是指已经由AbstractEntity类中的conflicts属性映射的多对多关系。因此,多对多关系的第二个定义不需要执行数据库更新,因为数据库更新由AbstractEntity拥有

在您显示的用于保存数据的代码中,您有已经持久化的事件对象。然后创建一个新的冲突类,并将关系添加到此类。问题是,当您持久化这个新类时,Hibernate将不会持久化关系,因为多对多定义表示事件对象拥有数据库更新。因此,要解决此问题,您可以更改映射,使其在冲突类中声明,并且AbstractEntity使用“mappedBy”属性声明对应项,或者可以持久化冲突类,然后使用事件类定义关系并更新它们。比如:

Event event1 = EventDAO.getInstance().get(eventID1);
Event event2 = EventDAO.getInstance().get(eventID2);
Conflict conflict = new Conflict();
session.save(conflict);
event1.getConflicts().add(conflict);
session.update(event1);
event2.getConflicts().add(conflict);
session.update(event2);

事实证明,问题不在Hibernate注释中。相反,问题在于我如何访问带注释方法中的集合

正如您在问题中所看到的,集合设置器清除集合,然后在新集合中添加任何项。更新后的代码(有效!)如下所示:

Event event1 = EventDAO.getInstance().get(eventID1);
Event event2 = EventDAO.getInstance().get(eventID2);
Conflict conflict = new Conflict();
conflict.getAffectedEntities().add(event1);
conflict.getAffectedEntities().add(event2);
@ManyToMany(targetEntity = AbstractEntity.class,
        fetch = FetchType.LAZY)
@JoinTable(name = "conflict_affected_entity",
        joinColumns = { @JoinColumn(name = "conflict_id", referencedColumnName = "id") },
        inverseJoinColumns = { @JoinColumn(name = "affected_entity_id", referencedColumnName = "id") })
public Set<AbstractEntity> getAffectedEntities()
{
    Hibernate.initialize(affectedEntities);
    return affectedEntities;
}

public void setAffectedEntities(Set<AbstractEntity> affectedEntities)
{
    this.affectedEntities = affectedEntities;
}

我将AbstractEntity上的@ManyToMany映射更改为您建议的。我在两个表上都有一些真正无聊的
id
字段作为主键,我在映射中使用了这些字段,但Hibernate行为没有改变。尝试的映射是:`@JoinTable(name=“conflict\u infected\u entity”,joinColumns={@JoinColumn(name=“infected\u entity\u id”,referencedColumnName=“id”)},inverseJoinColumns={@JoinColumn(name=“conflict\u id”,referencedColumnName=“id”)}),您的级联设置是什么?您在哪些实体上调用save?对于如上所示的代码,当抽象实体被添加到冲突实体中时,它们会被持久化,这让我感到惊讶,因为它似乎没有在关系上设置级联?@Hedley-看起来Hibernate文档指定默认配置了
PERSIST
MERGE
。我也尝试过指定
ALL
,但仍然没有成功。我编辑了问题以包含我用于提交新冲突的代码
@ManyToMany(targetEntity = Conflict.class,
        fetch = FetchType.LAZY)
@JoinTable(name = "conflict_affected_entity",
        joinColumns = { @JoinColumn(name = "affected_entity_id", referencedColumnName = "id") }, 
        inverseJoinColumns = { @JoinColumn(name = "conflict_id", referencedColumnName = "id") })
public Set<Conflict> getConflicts()
{
    Hibernate.initialize(conflicts);
    return conflicts;
}

public void setConflicts(Set<Conflict> conflicts)
{
    this.conflicts = conflicts;
}
for (AbstractEntity affectedEntity : toDelete.getAffectedEntities()) {
    notifications.add(Notification.forUsersWithAccess(ActionType.UPDATE, affectedEntity));
    // Forcefully remove the associations from the affectedEntity to the Conflict, since we don't want to risk using CascadeType.DELETE
    affectedEntity.getConflicts().remove(toDelete);
}
ConflictDAO.getInstance().delete(toDelete);