我虽然很简单,但我找不到解决问题的办法。我正在使用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

09-15 23:58