Как сделать так, чтобы Hibernate не увеличивал столбец версии родительского объекта при добавлении дочерних отношений коллекции (@ManyToMany)

Таблицы:

create table myuser.A (
  id number primary key,
  notes varchar2(50),
  version number);

create table myuser.B (
  id number primary key,
  username varchar2(50),
  version number);

create table myuser.A_B (
  a_id number,
  b_id number,
  constraint a_fk foreign key (a_id) references A(id),
  constraint b_fk foreign key (b_id) references B(id)
);

insert into myuser.A values ('1', 'notes', 1);
insert into myuser.B values ('44', 'username', 1);
insert into myuser.A_B values ('1', '44');

Аннотации Hibernate сопоставление:

@Entity
class A {

  @Id
  @Column
  public String id;

  @Column
  public String notes;

  @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
  @JoinTable(name = "A_B",
      joinColumns = { @JoinColumn(name = "A_ID") },
      inverseJoinColumns = { @JoinColumn(name = "B_ID") })
  public Set<B> bDomains;

  @Version
  public int version;
}

@Entity
class B {

  @Id
  @Column
  public String id;

  @Column
  public String username;

  @ManyToMany(fetch = FetchType.EAGER, mappedBy = "bDomains")
  public Set<A> aDomains;

  @Version
  public int version;
}

Получите существующий объект «A» и добавьте новый дочерний объект в коллекцию ManyToMany. Таким образом, объект «A» не меняется, но Hibernate генерирует для него новый номер версии и обновляет таблицу «A»:

A a = session.get(A.class, "1");
int versionBefore = a.version;

B b = new B();
b.id = "48";
b.username = "asd";

a.bDomains.add(b);

session.save(a);
session.flush();

int versionAfter = a.version;
System.out.println("version before: " + versionBefore);
System.out.println("version after: " + versionAfter);

Вывод:

Hibernate: select a0_.id as id1_0_0_, a0_.notes as notes2_0_0_, a0_.version as version3_0_0_, bdomains1_.A_ID as A_ID1_1_1_, b2_.id as B_ID2_1_1_, b2_.id as id1_2_2_, b2_.username as username2_2_2_, b2_.version as version3_2_2_ from A a0_, A_B bdomains1_, B b2_ where a0_.id=bdomains1_.A_ID(+) and bdomains1_.B_ID=b2_.id(+) and a0_.id=?
Hibernate: select adomains0_.B_ID as B_ID2_1_0_, adomains0_.A_ID as A_ID1_1_0_, a1_.id as id1_0_1_, a1_.notes as notes2_0_1_, a1_.version as version3_0_1_ from A_B adomains0_, A a1_ where adomains0_.A_ID=a1_.id and adomains0_.B_ID=?
Hibernate: select b_.id, b_.username as username2_2_, b_.version as version3_2_ from B b_ where b_.id=?
Hibernate: insert into B (username, version, id) values (?, ?, ?)
Hibernate: update A set notes=?, version=? where id=? and version=?
Hibernate: insert into A_B (A_ID, B_ID) values (?, ?)
version before: 1
version after: 2

Мне не нужен запрос UPDATE для таблицы, созданной спящим режимом, потому что таблица не изменяется в этой логике. Насколько я знаю, Hibernate увеличивает столбец версии при изменении любого поля объекта, даже если это поле является просто ссылкой на другую таблицу. Как я могу настроить Hibernate, чтобы предотвратить увеличение версии объекта, если изменилось только его отношение?


person Barataliba    schedule 06.07.2018    source источник
comment
пожалуйста, вы можете попробовать использовать @ElementCollection над вашими наборами A и B   -  person FrozzenFinger    schedule 06.07.2018


Ответы (1)


Я нашел решение. Необходимо добавить аннотацию @org.hibernate.annotations.OptimisticLock(excluded = true) к свойству @ManyToMany|@OneToMany.

Итак, сущность A из моего примера теперь выглядит так:

@Entity
class A {

  @Id
  @Column
  public String id;

  @Column
  public String notes;

  @org.hibernate.annotations.OptimisticLock(excluded = true)
  @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
  @JoinTable(name = "A_B",
      joinColumns = { @JoinColumn(name = "A_ID") },
      inverseJoinColumns = { @JoinColumn(name = "B_ID") })
  public Set<B> bDomains;

  @Version
  public int version;
}

Сгенерированные SQL:

Hibernate: select a0_.id as id1_0_0_, a0_.notes as notes2_0_0_, a0_.version as version3_0_0_, bdomains1_.A_ID as A_ID1_1_1_, b2_.id as B_ID2_1_1_, b2_.id as id1_2_2_, b2_.username as username2_2_2_, b2_.version as version3_2_2_ from A a0_, A_B bdomains1_, B b2_ where a0_.id=bdomains1_.A_ID(+) and bdomains1_.B_ID=b2_.id(+) and a0_.id=?
Hibernate: select adomains0_.B_ID as B_ID2_1_0_, adomains0_.A_ID as A_ID1_1_0_, a1_.id as id1_0_1_, a1_.notes as notes2_0_1_, a1_.version as version3_0_1_ from A_B adomains0_, A a1_ where adomains0_.A_ID=a1_.id and adomains0_.B_ID=?
Hibernate: select b_.id, b_.username as username2_2_, b_.version as version3_2_ from B b_ where b_.id=?
Hibernate: insert into B (username, version, id) values (?, ?, ?)
Hibernate: insert into A_B (A_ID, B_ID) values (?, ?)
version before: 1
version after: 1

Единственная проблема в том, что аннотация OptimisticLock взята из Hibernate, а не из JPA.

person Barataliba    schedule 08.07.2018