簡體   English   中英

休眠多對多聯接表對於繼承的實體不持久

[英]Hibernate Many-To-Many join table not persisting for inherited Entity

我已經閱讀了有關多對多關系的Hibernate文檔 ,並嘗試遵循他們的建議,但是我的解決方案並未成功。 希望有人可以闡明這個話題。

我有一個數據庫結構,試圖通過Hibernate映射多對多關系。 我的想法是,我有許多可能彼此沖突的實體。 在表結構方面,每個實體都是相似的,因此我從一個通用的持久化類AbstractEntity抽象了它們。 由於實體可能會發生沖突,並且可能與任何其他數量的實體發生沖突,因此我定義了一個單獨的Conflict休眠實體來定義每個沖突,每個沖突都應通過多對多關系映射到每個沖突該沖突中的實體。

這是實體聲明。 我已經將Event作為AbstractEntity Object具體實現的示例。

我的課程和休眠配置:

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

在代碼中,我需要能夠從任一側創建聯接表條目(將AbstractEntity添加到Conflict或將Conflict添加到AbstractEntity)。 下面顯示了如何創建示例的示例:

Event event1 = EventDAO.getInstance().get(eventID1);
Event event2 = EventDAO.getInstance().get(eventID2);
Conflict conflict = new Conflict();
conflict.getAffectedEntities().add(event1);
conflict.getAffectedEntities().add(event2);

Hibernate似乎對正在發生的事情有一個線索,所以我覺得我缺少一些簡單的東西。 當我創建一個新的Conflict並向其添加一個AbstractEntity時,會創建Conflict和AbstractEntity,但是聯接表仍然為空。 誰能為我提供線索以使Hibernate填寫空白加入表嗎?

您的表有主鍵嗎?

像這樣更改您的@ManyToMany映射:

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

根據所顯示的代碼(包括如何保存數據),問題出在什么實體擁有該關系。 在您的代碼中,您已將@ManyToMany映射到AbstractEntity類中,這意味着AbstractEntity及其子類是擁有該關系的類,並負責聯接表的數據庫更新。 在您的沖突類中,您已經正確定義了多對多關系,並使用

mappedBy = "conflicts"

您已經告訴Hibernate,多對多關系的第二個定義實際上是指AbstractEntity類中的flicts屬性已經映射的多對多關系。 因此,多對多關系的第二個定義不需要執行數據庫更新,因為數據庫更新由AbstractEntity擁有。

在顯示的用於保存數據的代碼中,您具有已經持久的Event對象。 然后,您創建一個新的Conflict類,並將關系添加到該類。 問題在於,當您持久化這個新類時,Hibernate將不會持久化該關系,因為多對多定義表明Event對象擁有數據庫更新。 因此,要解決此問題,您可以更改映射,以便在Conflict類中聲明它,然后AbstractEntity使用“ mappedBy”屬性聲明對應項,或者可以保留Conflict類,然后使用事件類,並對其進行更新。 就像是:

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批注中。 相反,問題出在我如何使用帶注釋的方法訪問集合。

正如您在問題中看到的那樣,“集合”設置器清除了集合,然后在新集合中添加了所有項目。 更新的代碼(有效!)在此處顯示:

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

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

對於將來的觀看者來說,這種Hibernate配置(將每一面映射為ManyToMany)會創建兩個單向關聯:從沖突-> AbstractEntities和從AbstractEntity->沖突。 這意味着,如果您決定使用此配置,則在添加或刪除集合中的項目時必須小心,以確保更新連接表條目,以避免違反外鍵約束。 例如,刪除沖突時,我們不能只說ConflictDAO.getInstance.delete(toDelete) 相反,我們必須確保沖突不保留任何關聯:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM