Hibernate et H2 “violation de contrainte d'intégrité Référentielle” pour OneToMany mise en correspondance bidirectionnelle
J'ai donc deux simples haricots -- FatKid et des Hamburgers. Maintenant, pour des raisons à mon insu, j'ai besoin d'être en mesure non seulement de rechercher tous les hamburgers quelqu'un a mangé, mais aussi qui a mangé particulier hamburger. Sur le code!
FatKid.java
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Table
@Entity
public class FatKid {
private int id;
private String name;
private List<Hamburger> hamburgers;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "FATKID_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name="HAMBURGER_ID")
public List<Hamburger> getHamburgers() {
return hamburgers;
}
public void setHamburgers(List<Hamburger> hamburgers) {
this.hamburgers = hamburgers;
}
}
Hamburger.java
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Table
@Entity
public class Hamburger {
private int id;
private String description;
private FatKid whoDoneAteMe;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "HAMBURGER_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="FATKID_ID")
public FatKid getWhoDoneAteMe() {
return whoDoneAteMe;
}
public void setWhoDoneAteMe(FatKid whoDoneAteMe) {
this.whoDoneAteMe = whoDoneAteMe;
}
}
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
<property name="hibernate.connection.url">jdbc:h2:~/routesetting</property>
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create-drop</property>
<mapping class="FatKid" />
<mapping class="Hamburger" />
</session-factory>
</hibernate-configuration>
dépendances
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.7.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.160</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.9.0.GA</version>
</dependency>
client
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class OmNom {
private static final SessionFactory sessionFactory = buildSessionFactory();
public static void main(String[] args) {
Session session = sessionFactory.openSession();
session.beginTransaction();
FatKid fk = new FatKid();
fk.setName("Darrell");
session.save(fk);
session.getTransaction().commit();
session.beginTransaction();
Hamburger hamburger_1 = new Hamburger();
hamburger_1.setDescription("Juicy quarter pounder with cheese");
hamburger_1.setWhoDoneAteMe(fk);
session.save(hamburger_1);
session.getTransaction().commit();
session.beginTransaction();
Hamburger hamburger_2 = new Hamburger();
hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg");
hamburger_2.setWhoDoneAteMe(fk);
session.save(hamburger_2);
session.getTransaction().commit();
sessionFactory.close();
}
private static SessionFactory buildSessionFactory() {
try {
//Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
//Make sure you log the exception, as it might be swallowed
throw new ExceptionInInitializerError(ex);
}
}
}
Donc, quand je lance le code, je me retrouve avec la sortie (et tronquée de la trace de la pile)
Hibernate: insert into FatKid (FATKID_ID, name) values (null, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Hibernate: insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [Hamburger]
...
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK43797FE95067143: PUBLIC.HAMBURGER FOREIGN KEY(HAMBURGER_ID) REFERENCES PUBLIC.FATKID(FATKID_ID)"; SQL statement:
insert into Hamburger (HAMBURGER_ID, description, FATKID_ID) values (null, ?, ?) [23506-160]
...
Donc le premier Hamburger est sauvé, mais il souffle alors sur la seconde. Les deux devraient être en mesure d'utiliser le FatKid de l'id de clé étrangère, mais il ne semble pas fonctionner. Aucune information serait grandement apprécié.
Grâce,
Kevin
OriginalL'auteur Kevin | 2011-10-23
Vous devez vous connecter pour publier un commentaire.
Vos mappages de l'air bizarre pour moi. Vous avez un @JoinColumn dans les deux côtés de la relation, chacun pointant vers la clé primaire de l'autre table. Qui ne semble pas être une relation OneToMany.
Votre OneToMany doit informer le propriétaire de la relation:
et puis dans l'autre côté:
Vous pourriez être en mesure d'optimiser votre code plus trop. Comme votre FatKid objets sont conscients de l'Hamburger objets et que vous avez configuré en cascade, vous pouvez faire:
Le code ci-dessus devrait enregistrer l'objet graphique avec juste une opération de validation et en une seule opération.
OriginalL'auteur Gonzalo Garcia Lasurtegui