我有多对一的关系,我希望可以为空:
@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
时,这确实是预期的行为吗?在这种情况下是否有解决方法来启用可为空的外键?
提前谢谢。
答案 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