2013-03-19 80 views
13

我有很多一对一的关系,我想可空:不能使@ManyToOne关系可空

@ManyToOne(optional = true) 
@JoinColumn(name = "customer_id", nullable = true) 
private Customer customer; 

不幸的是,JPA不断设置我的数据库中列NOT NULL。任何人都可以解释吗?有没有办法让它工作?请注意,我使用JBoss 7,JPA 2.0和Hibernate作为持久性提供者和PostgreSQL 9.1数据库。

编辑

,我发现我的问题的原因。显然,这是由于我的方式定义在引用的实体Customer主键:

@Entity 
@Table 
public class Customer { 
    @Id 
    @GeneratedValue 
    @Column(columnDefinition="serial") 
    private int id; 
} 

看来,使用@Column(columnDefinition="serial")主键自动设置外键在数据库中它引用到NOT NULL。当将列类型指定为serial时,这真的是预期的行为吗?在这种情况下是否有一种解决方法来启用可空的外键?

预先感谢您。

回答

9

我找到了我的问题的解决方案。主键在实体Customer中的定义方式没问题,问题在于外键声明。应该声明如下:

@ManyToOne 
@JoinColumn(columnDefinition="integer", name="customer_id") 
private Customer customer; 

事实上,如果省略该属性columnDefinition="integer"默认的外键将被设置为源列:非空系列都有自己的序列。这当然不是我们想要的,因为我们只是想引用自动递增的ID,而不是创建一个新ID。

此外,似乎属性name=customer_id也是需要的,因为我在执行一些测试时观察到。否则,外键列仍将被设置为源列。我认为这是一种奇怪的行为。欢迎发表评论或其他信息以便澄清此问题!

最后,这个解决方案的优点是ID由数据库生成(不是由JPA生成),因此当手动插入数据或通过经常发生在数据迁移或维护中的脚本时,我们不必担心。

0

这很奇怪。

在JPA中,可空参数默认为true。我一直使用这种配置,它工作正常。如果你试图保存实体,它应该是成功的。

您是否尝试删除为此关系创建的表?也许你有那个列的遗留表?

或者,您应该尝试在其他代码块上找到解决方案,因为这是正确的配置。

注:我已经在PostgreSQL上用JPA2和Hibernate尝试过这种配置。

编辑

在这种情况下,也许你可以尝试主键的一点点不同的定义。

例如,你可以使用定义是这样的:

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
@Column() 
private Long id; 

和PostgreSQL将产生

id bigint NOT NULL 
-- with constraint 
CONSTRAINT some_table_pkey PRIMARY KEY (id) 

如果这是不够好,你可以尝试此解决方案。

+0

这确实是我考虑的解决方案应运而生。不幸的是,这并不支持从数据库本身生成ID,而且这是手动插入数据时需要的功能(例如使用hibernate的import.sql)。幸运的是,我想我即将找到解决方案。我只是在做一些测试,如果成功,我会发布解决方案。谢谢你的帮助。 – vcattin 2013-03-23 23:34:19

7

我遇到了这个问题,但我还是能够解决这样说:

@ManyToOne 
@JoinColumn(nullable = true) 
private Customer customer; 

也许问题的声明@ManyToOne(optional = true)

+6

'nullable = false'? 'FALSE'?为什么是'假',而不是'真'? – Andremoniy 2015-05-19 09:15:08

+0

绝对应该是'nullable = true' – artificis 2016-11-16 14:28:11