2010-08-09 78 views
6

我有一个应用程序,我试图在使用Hibernate作为我的JPA提供程序的两个实体之间实现ManyToMany关系。由JPA产生的空连接表ManyToMany

我想要的例子是单向的,其中一个摄像头可以有多个镜头,而Lense可以适合多个摄像头。

以下是我的实体类...(只是粘贴它的相关部分)

摄像头:

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

    ... 
} 

镜头:

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

    ... 
} 

在测试情况下,我尝试坚持像这样的相机实例...

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

持久发生成功,并且没有Hibernate引发的错误/异常。但是,与预期相反,JoinTable中没有创建一行(在这种情况下为CAMERA_LENS)。仅在每个镜头和相机表格中创建一行,从而不符合ManyToMany的目的。但是,DDL是为连接表生成的,它也是创建的,但它只是没有任何记录。

任何援助或指针将不胜感激。

回答

5

我发现了这个问题。这有点奇怪。我用的是DAO类有一个类级别的注释:

@Transactional(readOnly=true) 

生成的SQL是

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

而且它仍然保存2个实体,但没有保存或将数据插入到连接表。

我添加的方法级别的注释的时刻:

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

一切都变成了要罚款,以及数据确实被插入到连接表。在这种情况下产生的新的sql语句是......

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

有点奇怪仍然没有成交传播史战略保存的数据为2个表,但一旦传播史的策略被赋予,一切都变成了要罚款。

另一个有趣的观察是,我尝试在方法级别上将传播策略作为强制(以检查是否存在导致第一个错误情况的事务),但是该方法抛出了表明没有事务存在的异常,数据仍保存在2个表格中。

希望可以帮助别人进一步...

+2

在我的情况下,这并没有帮助。有什么可以帮助我们刷新会话......(我仍然不明白为什么需要这样做,因为在事务内部看到的其他收集更新,只是这个中间表需要更新的地方没有看到。 – 2012-04-16 21:16:05

+0

我认为@Transactional(readOnly = true)可能仍然有一个默认传播,它是REQUIRED,它会启动一个tx。我遇到了同样的问题,使用@Transactional(progpagation = REQUIRED,readOnly = true)没有插入到连接表中。调用flush为@Adres建议工作,但也删除了readOnly – ams 2012-09-16 14:46:57