Однонаправленные отношения ManyToMany только для чтения - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть субъект Студент и субъект Курс .Один студент может быть связан с 0 или более Курсами .Viceversa, один курс может ассоциироваться с 0 или более студентами .

студентом субъектом:

@Data
@Entity(name = "student")
public class Student {

    @Id
    private Integer id;

    private String name;

    @ManyToMany(fetch = EAGER)
    @JoinTable(name = "student_course",
            joinColumns = @JoinColumn(
                    name = "studentId",
                    referencedColumnName = "id",
                    insertable = false,
                    updatable = false
            ),
            inverseJoinColumns = @JoinColumn(
                    name = "courseId",
                    referencedColumnName = "id",
                    insertable = false,
                    updatable = false)
    )
    private Collection<Course> courses;
}

Курс сущность:

@Data
@Entity(name = "course")
public class Course {

    @Id
    private Integer id;

    private String name;

    @ManyToMany(mappedBy = "courses")
    private Collection<Student> students;
}

и обратная ассоциация в сущности Курс .

Обе эти 2 @ ManyToMany ассоциациидолжен быть только для чтения.Моя проблема в том, что когда я пытаюсь сохранить Student Hibernate пытается обновить также связанную коллекцию.

Вот что Hibernate регистрирует при обновлении студента:

Hibernate: 
/* delete collection model.student.courses */ 
delete from `student_course` 
where `studentId`=?

Hibernate: 
/* insert collection row  */
insert into `student_course` (`studentId`, `courseId`) 
values (?, ?)

Как вы можете видеть, hibernate пытается обновить также таблицу, в которой хранятся связи между двумя объектами.Это те вопросы, которые я хочу избежать.

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Проблема в том, что list заказан, тогда как set нет.Обобщенный код для обновления списка, по-видимому, предполагает, что вы хотите сохранить этот порядок, поэтому он должен удалить весь список отношений и заново вставить его заново, чтобы сохранить порядок через идентификаторы PK отношения.Это было бы явно верно, если бы вы добавили аннотацию @OrderBy в свойстве соединения.В наборе это не нужно, поэтому он может просто вставить.

@Entity
@Data
@EqualsAndHashCode(of="id")
@NoArgsConstructor
public class E1 {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToMany
    Set<E2> e2s;

@Entity
@Data
@EqualsAndHashCode(of="id")
@NoArgsConstructor
public class E2 {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToMany(mappedBy="e2s")
    Set<E1> e1s;

И использовать их:

E1 e1 = new E1();
E2 e2 = new E2();
Set<E2> es2 = new HashSet<>();
es2.add(e2);
e1.setE2s(es2);

em.persist(e1);
em.persist(e2);
tx.commit();

// now modify the list
em.clear();

// fetch relations to avoid lazy fetch exception
e1 = em.createQuery("select e from E1 e left outer join fetch e.e2s where e.id = :id", E1.class)
        .setParameter("id", 1L)
        .getSingleResult();

tx.begin();
e2 = new E2();
e1.getE2s().add(e2);
em.persist(e2);
em.merge(e1);
tx.commit();

Это дает мне следующие журналы

create table E1_E2 (e1s_id bigint not null, e2s_id bigint not null, primary key (e1s_id, e2s_id))
create table E1 (id bigint generated by default as identity (start with 1), primary key (id))
create table E2 (id bigint generated by default as identity (start with 1), primary key (id))
alter table E1_E2 add constraint FKky9vffxlkk0u9t0ynqfsvanrt foreign key (e2s_id) references E2
alter table E1_E2 add constraint FKgnbwe4qtab0mt1caqxrrp8gqd foreign key (e1s_id) references E1
insert into E1 (id) values (default)
insert into E2 (id) values (default)
insert into E1_E2 (e1s_id, e2s_id) values (?, ?)
select e1x0_.id as id1_2_0_, e2x2_.id as id1_4_1_, e2s1_.e1s_id as e1_3_0__, e2s1_.e2s_id as e2_3_0__ from E1 e1x0_ left outer join E1_E2 e2s1_ on e1x0_.id=e2s1_.e1s_id left outer join E2 e2x2_ on e2s1_.e2s_id=e2x2_.id where e1x0_.id=?
insert into E2 (id) values (default)
insert into E1_E2 (e1s_id, e2s_id) values (?, ?)
0 голосов
/ 12 декабря 2018

Класс ученика:

@ManyToMany(fetch = LAZY)
@JoinTable(
    name="STUDENT_COURSE"
    , joinColumns={
        @JoinColumn(name="STUDENT_ID")
        }
    , inverseJoinColumns={
        @JoinColumn(name="COURSE_ID")
        }
    )
private List<Course> courses;

Класс курса:

@ManyToMany(mappedBy="courses")
private List<Student> students;

Как вы знаете, из спецификации JPA 2.0 выборка по умолчанию:

OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER

И в последней версии hibernate тип извлечения стремится по умолчанию для всех отображений, но если мы используем аннотации JPA, то он выравнивается со значениями по умолчанию JPA.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...