23

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

@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

4 回答 4

22

I found the solution to my problem. The way the primary key is defined in entity Customer is fine, the problem resides in the foreign key declaration. It should be declared like this:

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

Indeed, if the attribute columnDefinition="integer" is omitted the foreign key will by default be set as the source column: a not-null serial with its own sequence. That is of course not what we want as we just want the to reference the auto-incremented ID, not to create a new one.

Besides, it seems that the attribute name=customer_id is also required as I observed when performing some testing. Otherwise the foreign key column will still be set as the source column. This is a strange behavior in my opinion. Comments or additional information to clarify this are welcome!

Finally, the advantage of this solution is that the ID is generated by the database (not by JPA) and thus we do not have to worry about it when inserting data manually or through scripts which often happens in data migration or maintenance.

于 2013-03-24T00:59:50.003 回答
6

我遇到了这个问题,但我能够通过这种方式解决它:

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

也许问题是从声明中出现的@ManyToOne(optional = true)

于 2014-04-23T14:48:27.437 回答
0

这很奇怪。

在 JPA 中,可空参数默认为 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)

如果这足够好,您可以尝试此解决方案。

于 2013-03-20T15:53:15.240 回答
0

在事务内但在保存操作之前,将外键列值显式设置为空。通过这个休眠,永远不要对此外键相关表执行选择查询,并且不要抛出异常“在刷新之前保存瞬态实例”。如果您想有条件地设置“空值”,则执行 1. 使用 repo call get/find 获取并设置值 2. 然后检查条件的获取值并将其设置为 null 。粘贴下面的代码进行测试并找到工作

// 交易开始

   可选<客户> customerObject = customerRepository.findByCustomerId(customer.getCustomerId())

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

   否则 {yourEnclosureEntityObject.setCustomer(null)}

   yourEnclosureEntityObjectRepository.save(yourEnclosureEntityObject)

// 交易结束
于 2018-12-09T12:34:20.417 回答