我已阅读有关多对多关系的Hibernate Documentation,并尝试遵循他们的建议,但我的解决方案尚未成功。希望有人可以对这个话题有所了解。
我有一个数据库结构,我试图通过Hibernate映射多对多关系。我的想法是,我有许多实体可能互相冲突。表结构方面,这些实体中的每一个都是相似的,因此我将它们从一个常见的持久化类AbstractEntity
中抽象出来。由于实体可能存在冲突,并且可能与任何其他实体发生冲突,因此我定义了一个单独的Conflict
Hibernate实体来定义每个冲突,这些冲突应该通过多个映射进行映射。与冲突中的每个实体有很多关系。
以下是实体声明。我已将Event
作为AbstractEntity
对象的具体实现的示例。
我的类和休眠配置:
@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填入空白连接表吗?
答案 0 :(得分:0)
你的桌子有主键吗?
更改@ManyToMany映射:
@JoinTable(name = "conflict_affected_entity",
joinColumns = { @JoinColumn(name = "affected_entity_id", referencedColumnName="primaryKeyOfAffectedEntityColumnName") },
inverseJoinColumns = { @JoinColumn(name = "conflict_id", referencedColumnName="primaryKeyOfConflictColumnName") })
答案 1 :(得分:0)
根据您显示的代码,包括如何保存数据,问题在于实体拥有关系。在您的代码中,您已在AbstractEntity类中映射了@ManyToMany,这意味着AbstractEntity及其子类是拥有该关系的那些,并且负责连接表的数据库更新。在您的Conflict类中,您已正确定义了多对多关系,并使用
mappedBy = "conflicts"
你告诉Hibernate,多对多关系的第二个定义实际上指的是AbstractEntity类中的conflicts属性已经映射的多对多关系。因此,多对多关系的第二个定义不需要执行数据库更新,因为数据库更新由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);
答案 2 :(得分:0)
事实证明,问题不在Hibernate注释中。相反,问题在于我如何在带注释的方法中访问集合。
正如您在问题中所看到的,Collection setter清除了集合,然后在新集合中添加任何项目。更新的代码(有效!)如下所示:
@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)创建了两个单向关联:来自冲突 - &gt; AbstractEntities和AbstractEntity - &gt;冲突。这意味着,如果您决定使用此配置,则在添加或删除集合中的项目时必须小心,以确保更新连接表条目以避免外键约束违规。例如,在删除冲突时,我们不能只说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);