From 6fb8e408003d05564ca5c47b17ddf6689947786d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Mur=C3=ADn?= <xmurin@fi.muni.cz> Date: Mon, 29 Jul 2024 15:49:54 +0200 Subject: [PATCH] Allow for parallel User entity queries --- .../facade/TrainingDefinitionFacade.java | 13 +----- .../facade/TrainingInstanceFacade.java | 13 +----- .../repository/UserRefRepository.java | 2 +- .../repository/UserRefRepositoryCustom.java | 22 ++++++++++ .../repository/UserRefRepositoryImpl.java | 41 +++++++++++++++++++ .../adaptive/service/UserService.java | 15 ++++--- .../training/TrainingDefinitionService.java | 11 +---- .../training/TrainingInstanceService.java | 9 +--- .../service/training/TrainingRunService.java | 9 ++-- 9 files changed, 82 insertions(+), 53 deletions(-) create mode 100644 src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java create mode 100644 src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java index 9dff1a6b..16c76509 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java @@ -219,12 +219,6 @@ public class TrainingDefinitionFacade { trainingDefinitionService.update(mappedTrainingDefinition); } - private User createUserRefFromDTO(UserRefDTO userToBeCreated) { - User user = new User(); - user.setUserRefId(userToBeCreated.getUserRefId()); - return user; - } - /** * Clones Training Definition by id * @@ -359,11 +353,8 @@ public class TrainingDefinitionFacade { if (actualAuthorsIds.contains(author.getUserRefId())) { continue; } - try { - trainingDefinition.addAuthor(userService.getUserByUserRefId(author.getUserRefId())); - } catch (EntityNotFoundException ex) { - trainingDefinition.addAuthor(userService.createUserRef(createUserRefFromDTO(author))); - } + User user = userService.createOrGetUserRef(author.getUserRefId()); + trainingDefinition.addAuthor(user); } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java index 26a53056..69c07477 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java @@ -197,11 +197,8 @@ public class TrainingInstanceFacade { if (actualOrganizersIds.contains(organizer.getUserRefId())) { continue; } - try { - trainingInstance.addOrganizer(userService.getUserByUserRefId(organizer.getUserRefId())); - } catch (EntityNotFoundException ex) { - trainingInstance.addOrganizer(userService.createUserRef(createUserRefFromDTO(organizer))); - } + User user = userService.createOrGetUserRef(organizer.getUserRefId()); + trainingInstance.addOrganizer(user); } } @@ -218,12 +215,6 @@ public class TrainingInstanceFacade { return users; } - private User createUserRefFromDTO(UserRefDTO userToBeCreated) { - User user = new User(); - user.setUserRefId(userToBeCreated.getUserRefId()); - return user; - } - /** * Deletes specific training instance based on id * diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java index c44943f6..f42c7f7d 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java @@ -13,7 +13,7 @@ import java.util.Set; * The JPA repository interface to manage {@link User} instances. */ @Repository -public interface UserRefRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User> { +public interface UserRefRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User>, UserRefRepositoryCustom { /** * Find all users by userRefIds. diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java new file mode 100644 index 00000000..158c5286 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java @@ -0,0 +1,22 @@ +package cz.muni.ics.kypo.training.adaptive.repository; + +import cz.muni.ics.kypo.training.adaptive.domain.User; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.repository.query.Param; + +import javax.transaction.Transactional; + + +public interface UserRefRepositoryCustom { + + /** + * Insert user reference if it does not exist in the database. + * + * @param userRefId the user reference id + * @return the number of rows affected + */ + @Modifying + @Transactional + User createOrGet(@Param("userRefId") Long userRefId); + +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java new file mode 100644 index 00000000..4324a206 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java @@ -0,0 +1,41 @@ +package cz.muni.ics.kypo.training.adaptive.repository; + +import cz.muni.ics.kypo.training.adaptive.domain.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Repository; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +@Repository +public class UserRefRepositoryImpl implements UserRefRepositoryCustom { + + private static final Logger LOG = LoggerFactory.getLogger(UserRefRepositoryImpl.class); + + @PersistenceContext + private EntityManager entityManager; + + @Override + public User createOrGet(Long userRefId) { + int rowsAffected = entityManager.createNativeQuery("INSERT INTO \"user\" (user_ref_id) VALUES (:userRefId)" + + "ON CONFLICT DO NOTHING") + .setParameter("userRefId", userRefId) + .executeUpdate(); + + if (rowsAffected != 0) { + LOG.info("User with user_ref_id {} created", userRefId); + } + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); + Root<User> root = criteriaQuery.from(User.class); + criteriaBuilder.and(criteriaBuilder.equal(root.get("userRefId"), userRefId)); + return entityManager.createQuery(criteriaQuery).getSingleResult(); + } + + +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java index 6e78c324..0a8165f7 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java @@ -45,15 +45,14 @@ public class UserService { } /** - * Create new user reference + * If user reference with given user id does not exist, it is created and returned. + * Otherwise, the existing one is returned. * - * @param userToCreate user reference to be created - * @return created {@link User} + * @param userRefId id of the referenced user + * @return user reference with given referenced id */ - @TransactionalWO - public User createUserRef(User userToCreate) { - User user = userRefRepository.save(userToCreate); - LOG.info("User ref with user_ref_id: {} created.", user.getUserRefId()); - return user; + public User createOrGetUserRef(Long userRefId) { + return userRefRepository.createOrGet(userRefId); } + } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java index 2648a26c..5005ff31 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java @@ -456,14 +456,7 @@ public class TrainingDefinitionService { } private void addLoggedInUserToTrainingDefinitionAsAuthor(TrainingDefinition trainingDefinition) { - Long loggedInId = userManagementServiceApi.getLoggedInUserRefId(); - Optional<User> user = userRefRepository.findUserByUserRefId(loggedInId); - if (user.isPresent()) { - trainingDefinition.addAuthor(user.get()); - } else { - User newUser = new User(loggedInId); - userRefRepository.saveAndFlush(newUser); - trainingDefinition.addAuthor(newUser); - } + User user = userRefRepository.createOrGet(userManagementServiceApi.getLoggedInUserRefId()); + trainingDefinition.addAuthor(user); } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java index 7aebe488..67d73f06 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java @@ -214,13 +214,8 @@ public class TrainingInstanceService { } private void addLoggedInUserAsOrganizerToTrainingInstance(TrainingInstance trainingInstance) { - Optional<User> authorOfTrainingInstance = organizerRefRepository.findUserByUserRefId(userManagementServiceApi.getLoggedInUserRefId()); - if (authorOfTrainingInstance.isPresent()) { - trainingInstance.addOrganizer(authorOfTrainingInstance.get()); - } else { - User user = new User(userManagementServiceApi.getLoggedInUserRefId()); - trainingInstance.addOrganizer(organizerRefRepository.save(user)); - } + User userRef = organizerRefRepository.createOrGet(userManagementServiceApi.getLoggedInUserRefId()); + trainingInstance.addOrganizer(userRef); } /** diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java index fd77628a..b4b955ae 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java @@ -590,12 +590,9 @@ public class TrainingRunService { TrainingRun newTrainingRun = new TrainingRun(); newTrainingRun.setCurrentPhase(currentPhase); - Optional<User> userRefOpt = participantRefRepository.findUserByUserRefId(participantRefId); - if (userRefOpt.isPresent()) { - newTrainingRun.setParticipantRef(userRefOpt.get()); - } else { - newTrainingRun.setParticipantRef(participantRefRepository.save(new User(userManagementServiceApi.getLoggedInUserRefId()))); - } + User userRef = participantRefRepository.createOrGet(participantRefId); + newTrainingRun.setParticipantRef(userRef); + newTrainingRun.setState(TRState.RUNNING); newTrainingRun.setTrainingInstance(trainingInstance); newTrainingRun.setStartTime(startTime); -- GitLab