I have two entities:
@Setter
@Getter
@Entity
@Table(name = "Task")
@NoArgsConstructor
public class TaskEntity implements AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "mapName")
private String mapName;
@Column(name = "mapPath")
private String mapPath;
@Column(name = "mapCost")
private String mapCost;
@Column(name = "mapCostResult")
private String mapCostResult;
@Enumerated(EnumType.STRING)
@Column(name = "taskStatus")
private TaskStatus taskStatus;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "ticketId")
private TicketEntity ticket;
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "Builder_Task",
joinColumns = @JoinColumn(name = "taskId"),
inverseJoinColumns = @JoinColumn(name = "builderDiscordId")
)
private Set<BuilderEntity> builders = new HashSet<>();
public @NotNull TaskEntity addBuilder(@NotNull BuilderEntity builderEntity) {
builders.add(builderEntity);
return this;
}
public @NotNull TaskEntity removeBuilder(@NotNull BuilderEntity builderEntity) {
builders.remove(builderEntity);
return this;
}
}
and
@Setter
@Getter
@Entity
@Table(name = "Ticket")
@NoArgsConstructor
public class TicketEntity implements AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "channelId", unique = true)
private String channelId;
@Column(name = "creatorName")
private String creatorName;
@Column(name = "creationDate")
@CreationTimestamp
private Timestamp creationDate;
@Column(name = "deadline", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Timestamp deadline;
@Column(name = "available")
private boolean available;
@Column(name = "mapsAmount")
private int mapsAmount;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "ticket", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderColumn(name = "ticketId")
private Set<TaskEntity> tasks = new HashSet<>();
public @NotNull TicketEntity addTask(@NotNull TaskEntity taskEntity) {
tasks.add(taskEntity);
return this;
}
public @NotNull TicketEntity removeTask(@NotNull TaskEntity taskEntity) {
tasks.remove(taskEntity);
return this;
}
}
Here are my service and repository:
public class TicketRepository implements CRUDRepository<TicketEntity, Integer> {
// Only needed function for question
@Override
public @NotNull TicketEntity update(@NotNull TicketEntity ticketEntity) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
session.merge(ticketEntity);
transaction.commit();
return ticketEntity;
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
throw e;
}
}
}
public class TicketService {
public @NotNull Optional<TicketEntity> addTask(@NotNull Integer ticketId, @NotNull TaskEntity task) {
return updateTicketEntity(ticketId, ticketEntity -> {
ticketEntity.addTask(task);
task.setTicket(ticketEntity);
});
}
private @NotNull Optional<TicketEntity> updateTicketEntity(@NotNull Integer ticketId, @NotNull Consumer<TicketEntity> updater) {
Optional<TicketEntity> entity = findById(ticketId);
return Preconditions.checkAndReturn(entity.isPresent(),
() -> {
TicketEntity ticketEntity = entity.get();
updater.accept(ticketEntity);
TicketEntity savedEntity = ticketRepository.update(ticketEntity);
ticketCache.put(ticketId, savedEntity);
return Optional.of(savedEntity);
},
Optional::empty);
}
}
So, when I add the TaskEntity value into TicketEntity tasks Collection and merging to database, then all the values that were in the tasks are saved, but with a new ID (11 - first saving, 12 - second). All that I need is saving the collection but without duplicates.
Finally, the problem was that I didn't add the task inside the transaction
public TicketEntity addTask(int ticketId, TaskEntity taskEntity) {
Transaction transaction = null;
TicketEntity ticketEntity = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
ticketEntity = session.get(TicketEntity.class, ticketId);
if (ticketEntity == null) {
throw new IllegalArgumentException("Ticket not found with ID: " + ticketId);
}
taskEntity.setTicket(ticketEntity);
ticketEntity.addTask(taskEntity);
session.merge(ticketEntity);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
return ticketEntity;
}