2012-06-08 65 views
0

虽然它很简单,但我找不到任何解决方案。我使用的是playframework 1.2.3,它使用Hibernate作为JPA。所以我认为playframework与这个问题无关。JPA实体设计/无法删除实体

我有一些类(I省略非相关字段)

public class User { 
    ... 
} 

public class Task { 
    public DataContainer dataContainer; 
} 

public class DataContainer { 
    public Session session; 
    public User user; 
} 

public class Session { 
    ... 
} 

所以,我有关联从任务以DataContainer和从DataContainer到Sesssion和DataContainer属于用户。 DataContainers可以始终具有相同的用户,但每个实例的会话必须不同。而且任务的DataContainer在每种情况下也都不相同。一个DataContainer可以有一个Sesesion或不(它是可选的)。我只使用单向联想。它应该是足够的。

换句话说:每个任务必须有一个DataContainer。每个DataContainer 必须有一个/相同的用户和可以有一个会话。

要创建我使用JPA注释的DB模式:

@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 { 
    ... 
} 

BTW:型号是一出戏类,提供了主ID,只要型。

当我为每个实体创建一个对象并'连接它们',我的意思是关联,它工作正常。但是,当我尝试删除一个会话时,我得到了一个违反约束的异常,因为DataContainer仍然引用了我想要删除的会话。

我希望DataContainer的Session(字段)将分别设置为null,外键(session_id)应该在数据库中取消设置。这将是可以的,因为它可选。

我不知道,我想我有多个问题。我是否使用了正确的注释@OneToOne

我在互联网上发现了一些额外的注释和属性: @JoinColumnmappedBy属性为反比关系。但我没有,因为它不是双向的。或者是双向关联。本质?

另一次尝试是使用@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和用户将被删除。这对我来说是错误的。


编辑: 我使用PostgreSQL 9,JDBC的东西,包括在玩,我唯一的数据库配置是
db=postgres://app:[email protected]:5432/app

+0

也许这个作品:加'@OneToOne DataContainer'成'Session'和修改DataContainer会话属性'@OneToOne (的mappedBy = “dataContainer”)'。这样'DataContainer'类不再需要'session_id'列。 –

回答

3

您应该使用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 
+0

噢,这其实并不难。我只能用JPA注解来解决它。在删除会话之前,我使用第一个选项并在DataContainer上设置会话为空:我重写Session控制器中的_delete方法,并在调用super._delete()之前执行它。 – timaschew

0

不知道,但使用什么数据库?是由hibernate自动加载的,还是使用自己的DDL查询来创建它。如果是这样,请检查数据库级别是否建立了约束,请验证DataContainer表中的sessionId外键是否可以为空

+0

对不起,我忘了。我使用postgresql 9 – timaschew