2010-08-09 4 views
6

J'ai une application dans laquelle j'essaye d'implémenter la relation ManyToMany entre 2 entités utilisant Hibernate comme fournisseur JPA.Tableau de jointure vide résultant de JPA ManyToMany

L'exemple que j'essaie est un exemple unidirectionnel, dans lequel une caméra peut avoir plusieurs objectifs et la lentille peut s'adapter à plusieurs caméras.

Ce qui suit est ma classe d'entité ... (Il suffit de coller la partie pertinente de celui-ci)

Appareil photo:

@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>(); 

    ... 
} 

Objectif:

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

    ... 
} 

Dans le test cas, je essayer de persister l'instance de caméra comme ceci ...

@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 persistance se produit avec succès, et aucune erreur/exception n'est renvoyée par Hibernate. Cependant, contrairement aux attentes, une ligne n'est pas créée dans le JoinTable (CAMERA_LENS dans ce cas). Une ligne est créée uniquement dans chacune des tables de l'objectif et de la caméra, ne servant donc pas le but de ManyToMany. Cependant, le DDL est généré pour la table de jointure et il est également créé, mais il ne contient aucun enregistrement.

Toute aide ou pointeur serait grandement appréciée.

Répondre

5

J'ai trouvé le problème. C'est un peu bizarre. La classe DAO que j'utilisais avait une annotation de niveau de classe:

@Transactional(readOnly=true) 

Le SQL généré était

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

Et encore sauvé les 2 entités, mais n'a pas enregistré ou insérer des données dans la jointure table.

Au moment où j'ajouté une annotation de niveau de la méthode de:

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

tout se est avéré être bien, et les données ont été bien inséré dans la table de jointure. Les nouveaux SQLs générés dans ce cas était ...

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 (?, ?) 

encore un peu bizarre qu'aucune stratégie de transaction enregistrée propogation données dans 2 tables, mais une fois que la stratégie a été donnée propogation, tout se révélèrent bien. Une autre observation intéressante est que j'ai essayé de mettre la stratégie de propagation comme OBLIGATOIRE au niveau de la méthode (pour vérifier s'il existait une Transaction qui a conduit au premier cas), mais la méthode a émis une exception indiquant qu'aucune transaction n'existait , toujours les données ont été enregistrées dans les 2 tables.

Espérons que quelqu'un aide plus loin ...

+2

Dans mon cas, cela n'a pas aidé. Qu'est-ce que l'aide a été la vidange de la session ... (Je ne comprends toujours pas pourquoi cela était nécessaire, comme d'autres mises à jour de la collection vu dans la transaction, juste celle où la table intermédiaire avait besoin d'une mise à jour. –

+0

Je pense que @Transactional (readOnly = true) pourrait encore avoir une propagation par défaut qui est REQUIRED qui commencerait un tx.J'ai rencontré le même problème et obtenir @Transactional (progpagation = REQUIRED, readOnly = true) n'insérait pas dans la table de jointure. Appeler flush comme @Adres suggère travaillé, mais a également supprimé readOnly – ams

Questions connexes