2010-08-09 7 views
6

Tengo una aplicación en la que estoy tratando de implementar la relación ManyToMany entre 2 entidades usando Hibernate como mi proveedor JPA.Tabla de unión vacía resultante de JPA ManyToMany

El ejemplo que estoy tratando es unidireccional, en el que una cámara puede tener múltiples lentes y Lense puede caber en varias cámaras.

que sigue es mi entidad de clase ... (Sólo pegar la parte pertinente de la misma)

Cámara:

@Entity 
@Table(name = "CAMERAS") 
public class Camera implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "CAM_ID", nullable = false) 
    private Long camId; 

    @Column(name="CAMERA_BRAND") 
    private String cameraBrand; 

    @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE},fetch=FetchType.EAGER) 
    @JoinTable(name="CAMERA_LENS",[email protected](name="CAM_ID"),[email protected](name="LENS_ID")) 
     private Set<Lens> lenses = new HashSet<Lens>(); 

    ... 
} 

lente:

@Entity 
@Table(name = "LENSES") 
public class Lens implements Serializable {   
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "LENS_ID", nullable = false) 
    private Long lensId; 

    @Column(name="LENS_NAME") 
    private String name; 

    ... 
} 

En el caso de prueba, me intenta persistir la instancia de la cámara como esta ...

@Test 
public void test_saveCameraLenseManyToMany() { 
    Camera cam = new Camera(); 
    cam.setCameraBrand("Nikon"); 
    Set<Camera> cameras = new HashSet<Camera>(); 
    cameras.add(cam); 

    Set<Lens> lenses = new HashSet<Lens>(); 
    Lens lens1 = new Lens(); 
    lens1.setName("WideAngle"); 
    lenses.add(lens1); 

    cam.setLenses(lenses); 

    // concreteDAO.saveLens(lens1); 
    concreteDAO.saveCamera(cam); 
} 

La persistencia se realiza correctamente y Hibernate no produce ningún error/excepción. Sin embargo, contrariamente a lo esperado, no se crea una fila en JoinTable (CAMERA_LENS en este caso). Se crea una fila en cada una de las tablas de Lentes y Cámara únicamente, lo que no cumple el propósito de ManyToMany. Sin embargo, el DDL se genera para la tabla de unión y también se crea, pero solo que no tiene ningún registro.

Cualquier ayuda o punteros sería muy apreciada.

Respuesta

5

Encontré el problema. Es un poco raro La clase DAO que estaba usando tuvo una anotación de nivel de clase de:

@Transactional(readOnly=true) 

el SQL generado fue

Hibernate: insert into CAMERAS (CAMERA_BRAND) values (?) 
Hibernate: insert into LENSES (LENS_NAME) values (?) 
Hibernate: insert into LENSES (LENS_NAME) values (?) 

Y todavía guarda las 2 entidades, pero no guardar o insertar datos en la unión mesa.

El momento he añadido un nivel de anotación método:

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 

todo resultó ser bien, y de hecho los datos se insertan en la tabla de unión. Los nuevos LSQ generados en este caso fue ...

Hibernate: insert into CAMERAS (CAMERA_BRAND) values (?) 
Hibernate: insert into LENSES (LENS_NAME) values (?) 
Hibernate: insert into LENSES (LENS_NAME) values (?) 

Hibernate: insert into CAMERAS_LENSES (CAM_ID, LENS_ID) values (?, ?) 
Hibernate: insert into CAMERAS_LENSES (CAM_ID, LENS_ID) values (?, ?) 

un poco raro todavía que ninguna estrategia de propagación de transacciones guarda los datos en las tablas 2, pero una vez que se le dio la estrategia de propagación, todo resultó ser muy bien.

Otra observación interesante es que traté de poner la estrategia de propagación como OBLIGATORIA en el nivel del método (para verificar si existía una Transacción que condujo al primer y defectuoso caso), pero el método arrojó una excepción que indicaba que no existía ninguna transacción , aún los datos se guardaron en las 2 tablas.

Espero que ayude a alguien más en ...

+2

En mi caso, esto no ayudó. Lo que sí ayudó fue enjuagar la sesión ... (Todavía no entiendo por qué fue necesario, ya que otras actualizaciones de la colección se veían en la transacción. No se veía esta en la que la tabla intermedia necesitaba una actualización. Ir a la figura) –

+0

Creo que @Transactional (readOnly = true) aún podría tener una propagación predeterminada que es OBLIGATORIO, lo que iniciaría un tx.Me encontré con el mismo problema y obtener @Transactional (progpagation = REQUIRED, readOnly = true) no estaba insertando en la tabla de unión. Llamar a Flush como @Adres sugiere que funcionó, pero también lo hizo eliminar readOnly – ams

Cuestiones relacionadas