Reputation: 4109
I'm trying to persist a very simple Unidirectional One to Many relationship, but EclipseLink (2.3.1) fails.
Service Class (Parent):
@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;
}
Parameter Class (Child):
(Of course there is "service_id" foreign key field in the database, which is not represented in the class, as it's unidirectional relation).
@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;
}
And this is the code for Entity persistence:
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();
I get this exception:
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]
EDIT: The database field service_id
has (and should have) not-null constraint, due the nature of the data.
Is this a bug or is something wrong in the code?
Upvotes: 28
Views: 28213
Reputation: 121
By default nullable is true on @JoinColumn, while persisting the data in one to many relationship, we need to make nullable as false to avoid data violation exceptions that occurs at run-time.
Upvotes: 2
Reputation: 1829
I was able to get it to work in Oracle by using a deferrable foreign key.
Example:
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
Upvotes: 1
Reputation: 431
Use nullable = false
, on @JoinColumn
:
@JoinColumn(name = "service_id", nullable = false)
Upvotes: 43
Reputation: 4220
As I found out, in such cases, foreign key is filled in a separate statement. In my example, I used Address
entity with customer_id
as foreign key.
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]
Therefore, having @JoinColumn
with nullable=true
causes an error.
As alternative, you can use @OneToMany (..., orphanRemoval = true, ...)
.
Upvotes: 0
Reputation: 85
You can change your persistence for hibernate version<4.0 and your code will run well."Well" in reference " for one-to-many relation save/persist parent ONLY, NOT save/persist child's collection by separate task"
Upvotes: 1
Reputation: 21165
Try removing the not null constraint on the Parameter table's service_id field. Eclipselink will update the foreign key for unidirectional 1:m join columns in a separate statement, so you'll need to disable or delay the constraint check. Making it bidirectional will allow the fp field to be updated with the rest of the parameter data.
Upvotes: 16