gamliela
gamliela

Reputation: 4109

JPA - Persisting a Unidirectional One to Many relationship fails with EclipseLink

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

Answers (6)

SreeNath
SreeNath

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

jc12
jc12

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

William Ferreira
William Ferreira

Reputation: 431

Use nullable = false, on @JoinColumn:

@JoinColumn(name = "service_id", nullable = false)

Upvotes: 43

kolobok_ua
kolobok_ua

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

Alexander
Alexander

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

Chris
Chris

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

Related Questions