我虽然很简单,但我找不到解决问题的办法。我正在使用playframework 1.2.3,并且正在使用Hibernate作为JPA。因此,我认为游戏框架与该问题无关。
我有一些课程(我忽略了不相关的字段)
public class User {
...
}
public class Task {
public DataContainer dataContainer;
}
public class DataContainer {
public Session session;
public User user;
}
public class Session {
...
}
因此,我具有从Task到DataContainer以及从DataContainer到Sesssion的关联,并且DataContainer属于用户。 DataContainers可以始终具有相同的用户,但是每个实例的会话必须不同。每个实例的Task的DataContainer也必须不同。 DataContainer是否可以具有Sesesion(它是最佳的)。我仅使用单向关联。应该足够了。
换句话说:每个Task必须具有一个DataContainer。每个DataContainer必须具有一个/相同的用户,并且可以具有一个会话。
要创建数据库模式,我使用JPA批注:
@Entity
public class User extends Model {
...
}
@Entity
public class Task extends Model {
@OneToOne(optional = false, cascade = CascadeType.ALL)
public DataContainer dataContainer;
}
@Entity
public class DataContainer extends Model {
@OneToOne(optional = true, cascade = CascadeType.ALL)
public Session session;
@ManyToOne(optional = false, cascade = CascadeType.ALL)
public User user;
}
@Entity
public class Session extends Model {
...
}
顺便说一句:模型是一个播放类,并提供主要ID作为long类型。
当我为每个实体创建一些对象并“连接它们”时,我的意思是关联,它可以正常工作。但是,当我尝试删除Session时,遇到了违反约束的异常,因为DataContainer仍然引用我要删除的Session。
我希望将DataContainer的会话(字段)设置为null或分别在数据库中未设置外键(session_id)。可以,因为它是可选的。
我不知道,我认为我有多个问题。我在使用正确的注释
@OneToOne
吗?我在互联网上发现了一些其他注释和属性:
@JoinColumn
和逆关系的mappedBy
属性。但是我没有它,因为它不是双向的。或者是双向关联。实质上?另一种尝试是使用
@OnDelete(action = OnDeleteAction.CASCADE)
,将约束从更新或删除时的NO ACTION
更改为:ADD CONSTRAINT fk4745c17e6a46a56 FOREIGN KEY (session_id)
REFERENCES annotation_session (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE;
但是在这种情况下,当我删除会话时,将删除DataContainer和User。对我来说这是错误的。
编辑:
我正在使用postgresql 9,jdbc的东西包含在播放中,我唯一的数据库配置是
db=postgres://app:app@localhost:5432/app
最佳答案
您应该使用OneToOne还是ManyToOne?使用最能描述情况的协会。如果多个DataContainer可能具有相同的会话,则为ManyToOne。如果只有一个DataContainer可以进行给定的会话,那么它就是OneToOne。
现在,如果删除会话,并且DataContainer仍引用该会话,则当然会出现异常。那就是FK的目的:它确保您没有引用不存在会话的DataContainer。因此,要删除会话,您应该首先更新引用它的所有数据容器。
由于您的关联是单向的,因此您将需要执行以下查询:
select dc from DataContainer dc where dc.session = :session
执行此查询,遍历结果,并将会话设置为null。然后,删除会话。
如果您的关联是双向的,则可以执行以下操作:
for DataContainer dc : session.getDataContainers() {
dc.setSession(null);
}
您也可以使用更新查询在单个查询中完成所有操作。但是请注意,不会对会话中已加载的DataContainers进行以下更改:
update DataContainer dc set dc.session = null where dc.session = :session