JPA - 使用 EclipseLink 保持单向一对多关系失败
Posted
技术标签:
【中文标题】JPA - 使用 EclipseLink 保持单向一对多关系失败【英文标题】:JPA - Persisting a Unidirectional One to Many relationship fails with EclipseLink 【发布时间】:2012-09-27 03:34:06 【问题描述】:我正在尝试保持一个非常简单的单向一对多关系,但 EclipseLink (2.3.1) 失败。
服务类(父):
@Entity
@Table(name = "tbl_service2")
public class Service implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="service_id")
public long serviceID;
@Column(name="name")
public String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="service_id", referencedColumnName="service_id")
public Set<Parameter> parameters;
参数类(子): (当然数据库中有“service_id”外键字段,类中没有表示,因为它是单向关系)。
@Entity
@Table(name = "tbl_service_parameters2")
public class Parameter implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="param_id")
public long parameterID;
@Column(name="name")
public String name;
这是实体持久化的代码:
Service service = new Service();
service.parameters = new HashSet<Parameter>();
service.name = "test";
Parameter param = new Parameter();
param.name = "test";
service.parameters.add(param);
em.persist(service);
em.flush();
我得到了这个例外:
Internal Exception: java.sql.SQLException: Field 'service_id' doesn't have a default value
Error Code: 1364
Call: INSERT INTO tbl_service_parameters2 (name) VALUES (?)
bind => [test]
编辑:由于数据的性质,数据库字段 service_id
具有(并且应该具有)非空约束。
这是一个错误还是代码中有问题?
【问题讨论】:
奇怪。您是否尝试过更新版本的 EclipseLink? 2.3.3 也许?也许这是一个错误。 @TimBedner 在 2.3.3 和 2.4.0 上也进行了测试,但没有运气。我在EclipseLink Bugzilla开了一个案例@ 您的代码看起来还不错。您想尝试使用 Batoo JPA 吗?如果失败,我可能会提供帮助。 batoo.jp 我已将第一个社区测试用例添加到 Batoo JPA :) 你的案例通过了...github.com/BatooOrg/BatooJPA/tree/master/community/src/test/… 我建议将映射关系移动到Parameter类。 @ManyToOne(cascade=CascadeType.ALL) @JoinColumn(name="service_id", referencedColumnName="service_id") 私有Service服务; 【参考方案1】:在@JoinColumn
上使用nullable = false
:
@JoinColumn(name = "service_id", nullable = false)
【讨论】:
我认为这是最好的答案,因为它几乎不会改变原始问题的任何前提。 谢谢,这解决了我的问题而无需更改任何其他内容。【参考方案2】:尝试删除 Parameter 表的 service_id 字段上的 not null 约束。 Eclipselink 将在单独的语句中更新单向 1:m 连接列的外键,因此您需要禁用或延迟约束检查。使其成为双向将允许 fp 字段使用其余参数数据进行更新。
【讨论】:
是否假设 OP 正在手动创建表?我假设表创建也被委托给 EclipseLink。 关系上没有非空注解,所以DDL gen不会加一个。 表是手动创建的,因此非空约束与 AFAIN 无关。使关系双向确实有效,但这是一种解决方法,不能回答问题。 如果没有非空约束,为什么 service_id 的异常没有值?如果删除约束,您将看到 EclipseLink 稍后更新 fk,因为它不受 Parameter 实体的控制。 存在非空约束。很抱歉,问题并不清楚,但我不明白为什么它是相关的。阅读***.com/questions/12755380 后,我意识到这可能是答案的一部分......【参考方案3】:您可以将您的持久性更改为休眠版本
【讨论】:
【参考方案4】:我能够通过使用可延迟外键使其在 Oracle 中工作。
例子:
ALTER TABLE my_table ADD CONSTRAINT my_constraint_name FOREIGN KEY (my_table_column) REFERENCES foreign_key_table (foreign_key_table_column) DEFERRABLE INITIALLY DEFERRED
【讨论】:
【参考方案5】:默认情况下,@JoinColumn 上的 nullable 为 true,在将数据以一对多关系持久化的同时,我们需要将 nullable 设置为 false,以避免在运行时发生数据违规异常。
【讨论】:
【参考方案6】:我发现,在这种情况下,外键会填写在单独的语句中。在我的示例中,我使用了 Address
实体和 customer_id
作为外键。
2014-07-08T20:51:12.752+0300|FINE: INSERT INTO ADDRESS (address_id, street, city, region) VALUES (?, ?, ?, ?)
bind => [10, foo, foo, foo]
2014-07-08T20:51:12.753+0300|FINEST: Execute query InsertObjectQuery(ua.test.customer.Address@28cef39d)
2014-07-08T20:51:12.757+0300|FINEST: Execute query DataModifyQuery(sql="UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)")
2014-07-08T20:51:12.757+0300|FINE: UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)
bind => [151, 10]
因此,将@JoinColumn
与nullable=true
结合使用会导致错误。
您也可以使用@OneToMany (..., orphanRemoval = true, ...)
。
【讨论】:
以上是关于JPA - 使用 EclipseLink 保持单向一对多关系失败的主要内容,如果未能解决你的问题,请参考以下文章
JPA 使用指南 /Eclipselink/JPA 实体生成器
JPA + EclipseLink+ HSQLDB 不创建表