JPA-la persistance D'une relation unidirectionnelle à plusieurs échoue avec EclipseLink
J'essaie de persister une relation unidirectionnelle un à plusieurs très simple, mais EclipseLink (2.3.1) échoue.
Classe De Service (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;
}
Classe De Paramètres (Enfant):
(Bien sûr, il y a un champ de clé étrangère "service_id" dans la base de données, qui n'est pas représenté dans la classe, car c'est une relation unidirectionnelle).
@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;
}
Et c'est le code pour la persistance de L'entité:
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();
Je reçois cette 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: La base de données le champ service_id
A (et devrait avoir) une contrainte not-null, en raison de la nature des données.
Est-ce un bug ou quelque chose ne va pas dans le code?
6 réponses
Essayez de supprimer la contrainte not null sur le champ service_id de la table des paramètres. Eclipselink mettra à jour la clé étrangère pour les colonnes unidirectionnelles 1:m join dans une instruction séparée, vous devrez donc désactiver ou retarder la vérification des contraintes. Le rendre bidirectionnel permettra au champ fp d'être mis à jour avec le reste des données du paramètre.
Utiliser nullable = false
, sur @JoinColumn
:
@JoinColumn(name = "service_id", nullable = false)
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 voliation exceptions that occurs at run-time
Vous pouvez changer votre persistance pour hibernate version
J'ai pu le faire fonctionner dans Oracle en utilisant une clé étrangère différable.
Exemple:
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
Comme je l'ai découvert, dans de tels cas, la clé étrangère est remplie dans une instruction séparée. Dans mon exemple, j'ai utilisé Address
entité avec customer_id
comme clé étrangère.
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]
Donc @JoinColumn
avec nullable=true
provoque une erreur.
, Comme alternative, vous pouvez utiliser @OneToMany (..., orphanRemoval = true, ...)
.