Reputation: 1323
Whenever I update UserEntity hibernate triggers an update on the related UserRoles table. I found similar issues here but could not find a working solution.
@Entity
@Table(name = "users")
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = AUTO)
private UUID uuid;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private String email;
@JsonIgnore private String password;
@JsonIgnore
@OneToMany(mappedBy = "user", fetch = LAZY, cascade = REMOVE)
@Builder.Default
private List<UserRoleEntity> roles = new ArrayList<>();
@Entity
@Table(name = "user_roles")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EntityListeners(AuditingEntityListener.class)
@TypeDef(name = "enum_postgres_sql", typeClass = PostgresEnumType.class)
public class UserRoleEntity {
@Id
@GeneratedValue(strategy = AUTO)
private UUID uuid;
@Column(name = "role")
@Enumerated(STRING)
@Type(type = "enum_postgres_sql")
private Role role;
@ManyToOne
@JoinColumn(name = "user_uuid", updatable = false)
private UserEntity user;
@Type(
type = "com.vladmihalcea.hibernate.type.array.ListArrayType",
parameters = {@Parameter(name = ListArrayType.SQL_ARRAY_TYPE, value = "permission")})
@Column(name = "permissions", columnDefinition = "permission[]")
@Builder.Default
private List<Permission> permissions = new ArrayList<>();
@CreatedBy @OneToOne private UserEntity createdBy;
@LastModifiedBy @OneToOne private UserEntity lastModifiedBy;
}
Create user:
UserEntity user =
UserEntity.builder()
.firstName(dto.getFirstName())
.lastName(dto.getLastName())
.email(dto.getEmail())
.createdAt(LocalDateTime.now())
.build();
repository.save(user);
Update user:
repository
.findById(uuid)
.ifPresentOrElse(
e -> {
e.setFirstName(dto.getFirstName());
e.setLastName(dto.getLastName());
if (!StringUtils.equals(dto.getEmail(), e.getEmail())) {
e.setEmail(dto.getEmail());
}
e.setUpdatedAt(LocalDateTime.now());
repository.save(e);
},
() -> {
LOGGER.error("UserEntity with uuid: {} not found", uuid);
throw new UserEntityNotFoundException(uuid);
});
Repo
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<UserEntity, UUID> {}
Does anyone have an idea how to prevent this?
The reason I want to prevent this is that I'm using triggers in Postgresql to write logs of user actions and unnecessary updates mess things up... :(
Here are some logs:
2021-07-07 01:17:04,748 INFO o.s.d.r.c.DeferredRepositoryInitializationListener:53 - Spring Data repositories initialized!
2021-07-07 01:17:04,768 INFO c.s.j.l.u.w.UserLogControllerGetCreatedUserIntegrationTest:61 - Started UserLogControllerGetCreatedUserIntegrationTest in 36.711 seconds (JVM running for 39.424)
2021-07-07 01:17:04,936 DEBUG c.s.j.t.m.DatabaseMixin:31 - TestContainers database properties: test@jdbc:postgresql://localhost:56611/test?loggerLevel=OFF
2021-07-07 01:17:05,112 DEBUG o.h.SQL:128 -
insert
into
users
(changed_by_uuid, company_uuid, created_at, email, first_name, last_name, password, status, type, updated_at, uuid)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2021-07-07 01:17:05,115 TRACE o.h.t.d.s.BasicBinder:52 - binding parameter [1] as [OTHER] - [null]
2021-07-07 01:17:05,115 TRACE o.h.t.d.s.BasicBinder:52 - binding parameter [2] as [OTHER] - [null]
2021-07-07 01:17:05,116 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [3] as [TIMESTAMP] - [2021-07-07T01:17:05.104298]
2021-07-07 01:17:05,117 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [4] as [VARCHAR] - [[email protected]]
2021-07-07 01:17:05,117 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [5] as [VARCHAR] - [John]
2021-07-07 01:17:05,118 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [6] as [VARCHAR] - [Doe]
2021-07-07 01:17:05,118 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [7] as [VARCHAR] - [$2a$10$woVXWhuoHEqoIZMlul6/4.cc.33AyTCUc8nDWDiqImuj0vqlY.PK.]
2021-07-07 01:17:05,118 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [10] as [TIMESTAMP] - [2021-07-07T01:17:05.104346]
2021-07-07 01:17:05,119 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [11] as [OTHER] - [4df92c40-fde1-4a09-bfe9-53f2deb2f41d]
2021-07-07 01:17:05,140 DEBUG o.h.SQL:128 -
insert
into
user_roles
(changed_by_uuid, permissions, role, user_uuid, uuid)
values
(?, ?, ?, ?, ?)
2021-07-07 01:17:05,140 TRACE o.h.t.d.s.BasicBinder:52 - binding parameter [1] as [OTHER] - [null]
2021-07-07 01:17:05,141 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [2] as [ARRAY] - [[Ljava.lang.Object;@24be7cee]
2021-07-07 01:17:05,152 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [4] as [OTHER] - [4df92c40-fde1-4a09-bfe9-53f2deb2f41d]
2021-07-07 01:17:05,153 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [5] as [OTHER] - [2fa664b9-f9cd-4092-a38b-c46d47c0ab95]
2021-07-07 01:17:05,156 DEBUG o.h.SQL:128 -
update
user_roles
set
changed_by_uuid=?,
permissions=?,
role=?,
user_uuid=?
where
uuid=?
2021-07-07 01:17:05,156 TRACE o.h.t.d.s.BasicBinder:52 - binding parameter [1] as [OTHER] - [null]
2021-07-07 01:17:05,157 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [2] as [ARRAY] - [[CREATE]]
2021-07-07 01:17:05,157 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [4] as [OTHER] - [4df92c40-fde1-4a09-bfe9-53f2deb2f41d]
2021-07-07 01:17:05,157 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [5] as [OTHER] - [2fa664b9-f9cd-4092-a38b-c46d47c0ab95]
2021-07-07 01:17:05,165 DEBUG o.h.SQL:128 -
insert
into
user_roles
(changed_by_uuid, permissions, role, user_uuid, uuid)
values
(?, ?, ?, ?, ?)
2021-07-07 01:17:05,165 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [1] as [OTHER] - [4df92c40-fde1-4a09-bfe9-53f2deb2f41d]
2021-07-07 01:17:05,165 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [2] as [ARRAY] - [[Ljava.lang.Object;@4bc4b33b]
2021-07-07 01:17:05,166 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [4] as [OTHER] - [4df92c40-fde1-4a09-bfe9-53f2deb2f41d]
2021-07-07 01:17:05,166 TRACE o.h.t.d.s.BasicBinder:64 - binding parameter [5] as [OTHER] - [afe1ed15-005f-4c2e-8d55-bd3db570dc2e]
2021-07-07 01:17:05,168 DEBUG o.h.SQL:128 -
update
user_roles
set
changed_by_uuid=?,
permissions=?,
role=?,
user_uuid=?
where
uuid=?
Upvotes: 0
Views: 605
Reputation: 1323
The permissions were mapped badly
This is the way it should look
permissions column is mutable and Hibernate flushes again because it can't determine dirtiness
The solution was:
@Type(
type = "com.vladmihalcea.hibernate.type.array.EnumArrayType",
parameters = {@Parameter(name = EnumArrayType.SQL_ARRAY_TYPE, value = "permission")})
@Column(name = "permissions", columnDefinition = "permission[]")
private Permission[] permissions;
Upvotes: 0
Reputation: 1323
Actually, it is a bug in the Hibernate: HHH-5855
I used List instead of Set in many-to-many
Upvotes: 1