2011-10-23 27 views
9

Tengo dos frijoles simples: FatKid y Hamburgers. Ahora, por razones que, sin mi conocimiento, debo ser capaz de buscar no solo todas las hamburguesas que alguien comió, sino también quién comió qué hamburguesa en particular. ¡En el código!Hibernate y H2 "Infracción de restricción de integridad referencial" para la asignación OneToMany bidireccional

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> 

dependencias

<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> 

cliente

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); 
     } 
    } 

} 

Así que cuando corro el código que terminan con la salida (y seguimiento de la pila truncada)

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] 
     ... 

Así que la primera hamburguesa se guarda pero luego explota en el segundo. Ambos deberían poder usar el ID de FatKid como su clave externa, pero parece que no funciona. Cualquier idea sería muy apreciada.

Gracias, Kevin

Respuesta

6

Sus asignaciones miran raro para mí. Tiene un @JoinColumn en ambos lados de la relación, cada uno apuntando a la clave primaria de la otra tabla. Eso no parece ser una relación OneToMany.

Su OneToMany debe decirle al dueño de la relación:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "whoDoneAteMe") 
public List<Hamburger> getHamburgers() { 
    return hamburgers; 
} 

y luego en el otro lado:

@ManyToOne(cascade = CascadeType.ALL) 
@JoinColumn(name = "fatkid_id") 
public FatKid getWhoDoneAteMe() { 
    return whoDoneAteMe; 
} 

Usted puede ser capaz de optimizar su código adicional también. A medida que los objetos FatKid son conscientes de los objetos hamburguesa y que han configurado en cascada, se podría hacer:

session.beginTransaction(); 
    FatKid fk = new FatKid(); 
    fk.setName("Darrell"); 

    Hamburger hamburger_1 = new Hamburger(); 
    hamburger_1.setDescription("Juicy quarter pounder with cheese"); 
    hamburger_1.setWhoDoneAteMe(fk); 
    fk.getHamburgers().add(hamburger1); 

    Hamburger hamburger_2 = new Hamburger(); 
    hamburger_2.setDescription("Ground buffalo burger topped with bacon and a sunny-side egg"); 
    hamburger_2.setWhoDoneAteMe(fk); 
    fk.getHamburgers().add(hamburger2); 

    session.save(fk); 
    session.getTransaction().commit(); 

    sessionFactory.close(); 

El código anterior debe guardar el gráfico de objetos completa con una sola operación de confirmación y en una sola transacción.

+0

Muchas gracias, eliminar ese @JoinColumn adicional y agregar mappedBy lo hizo funcionar. – Kevin

Cuestiones relacionadas