簡體   English   中英

單向ManyToMany只讀關系

[英]Unidirectional ManyToMany readonly relationship

我有一個實體學生和一個實體課程 一名學生可以與0個或更多課程相關聯。 課程 ,一門課程可以有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;
}

和實體課程中的反向關聯。

這兩個@ManyToMany關聯都應該是readonly。 我的問題是,當我嘗試保存學生時, 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是試圖更新存儲在兩個實體之間的關聯的表。 這些是我想要避免的查詢。

學生班:

@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中,fetch類型對於所有映射都非常渴望,但如果我們使用JPA注釋,那么它與JPA默認值一致。

問題是list是有序的,而set則不是。 用於更新列表的通用代碼似乎假設您希望保留該順序,因此它必須刪除整個關系列表並重新插入它以通過關系PK ID保存順序。 如果在join屬性上添加了@OrderBy注釋,則顯式為true。 在一個集合中,這不是必需的,因此它可以只進行插入。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM