无法使@ManyToOne关系成为可空

时间:2013-03-19 22:40:53

标签: jpa-2.0 jboss7.x nullable postgresql-9.1 many-to-one

我有多对一的关系,我希望可以为空:

@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时,这确实是预期的行为吗?在这种情况下是否有解决方法来启用可为空的外键?

提前谢谢。

4 个答案:

答案 0 :(得分:11)

我找到了解决问题的方法。在实体Customer中定义主键的方式很好,问题在于外键声明。它应该像这样声明:

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

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

此外,正如我在执行某些测试时所观察到的那样,似乎还需要属性name=customer_id。否则,外键列仍将设置为源列。在我看来,这是一种奇怪的行为。欢迎提供评论或其他信息以澄清这一点!

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

答案 1 :(得分:7)

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

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

也许问题来自宣布@ManyToOne(optional = true)

答案 2 :(得分:0)

这很奇怪。

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

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

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

注意:我在使用JPA2和Hibernate的PostgreSQL上尝试过这种配置。

修改

在这种情况下,您可以尝试使用不同的主键定义。

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

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

和postgresql将生成

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

如果这个足够好你可以尝试这个解决方案。

答案 3 :(得分:0)

在事务内但在保存操作之前,将外键列值显式设置为null。通过这种休眠方式,切勿对此外键相关表执行选择查询,也不会抛出异常“在刷新之前保存瞬态实例”。如果要有条件地设置“空值”,则执行1.提取并使用回购调用get / find 2.设置该值,然后检查该条件的提取值并将其相应地设置为null。粘贴下面要测试的代码并发现有效

//  Transaction Start 

   Optional<Customer> customerObject = customerRepository.findByCustomerId(customer.getCustomerId())

   if(customerObject.isPresent())yourEnclosingEntityObject.setCustomer(customerObject)}

   else {yourEnclosingEntityObject.setCustomer(null)}

   yourEnclosingEntityObjectRepository.save(yourEnclosingEntityObject)

//  Transaction End