Пустая таблица соединений, полученная в результате JPA ManyToMany

У меня есть приложение, в котором я пытаюсь реализовать отношение ManyToMany между двумя объектами, используя Hibernate в качестве поставщика JPA.

Пример, который я пытаюсь использовать, является однонаправленным, в котором камера может иметь несколько объективов, а объектив может вписываться в несколько камер.

Ниже приведен мой класс сущностей... (Просто вставьте соответствующую его часть)

Камера:

@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",joinColumns=@JoinColumn(name="CAM_ID"),inverseJoinColumns=@JoinColumn(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) не создается. Строка создается только в каждой из таблиц Lens и Camera, что не служит цели ManyToMany. Тем не менее, DDL генерируется для таблицы соединений, и она также создается, но просто в ней нет никаких записей.

Любая помощь или указатели будут высоко оценены.


person PaiS    schedule 09.08.2010    source источник


Ответы (1)


Я нашел проблему. Это немного странно. Класс 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 таблицы.

Надеюсь, это поможет кому-то в дальнейшем...

person PaiS    schedule 09.08.2010
comment
В моем случае это не помогло. Что действительно помогло, так это сброс сеанса... (Я до сих пор не понимаю, зачем это было нужно, поскольку другие обновления коллекции были видны в транзакции. Только это, где промежуточная таблица нуждалась в обновлении, не было замечено. Пойди разберись) - person Andres F.; 17.04.2012
comment
Я думаю, что @Transactional(readOnly=true) все еще может иметь распространение по умолчанию, которое НЕОБХОДИМО, чтобы запустить tx. Я столкнулся с той же проблемой, и получение с помощью @Transactional(progpagation=REQUIRED,readOnly=true) не вставлялось в таблицу соединений. вызов флеша, как предлагает @Adres, работал, но удаление readOnly тоже. - person ams; 16.09.2012