3

Tables:

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');

Annotations Hibernate mapping:

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

Get existing 'A' object and add new child object to ManyToMany collection. So 'A' object doesn't change, but Hibernate generates a new version number for it and updates 'A' table:

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

Output:

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

I don't need UPDATE query on A table which is generated by hibernate, because A table is not changed in this logic. As I know Hibernate increments version column on changing any field of an entity, even though this field is just a reference to another table. How can I configure Hibernate to prevent incrementing version of an entity if only its relationship changed?

1
  • please can you try to use @ElementCollection above your sets of A and B Commented Jul 6, 2018 at 17:05

1 Answer 1

1

I found a solution. Need to add @org.hibernate.annotations.OptimisticLock(excluded = true) annotation on @ManyToMany|@OneToMany property.

So, A entity from my example looks like this now:

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

Generated SQLs:

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

The only problem is that OptimisticLock annotation is from Hibernate, not from JPA.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.