From d497ed108e5d01584b74c61fd98ab3fc12851c3f Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 29 Dec 2025 12:55:00 +0100 Subject: [PATCH] fix(server): fix duplicate Ingredient present in each recipe An issue where multiple instances of a uniquely named Ingredient are stored in the database. This is patched by checking server-side whether an ingredient exists before persisting it. This now correctly implements the Many-to-Many reference. --- .../java/server/api/RecipeController.java | 34 +++++++++++-------- .../server/database/IngredientRepository.java | 2 ++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/server/src/main/java/server/api/RecipeController.java b/server/src/main/java/server/api/RecipeController.java index 3a479cb..2a56310 100644 --- a/server/src/main/java/server/api/RecipeController.java +++ b/server/src/main/java/server/api/RecipeController.java @@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import server.database.IngredientRepository; import server.database.RecipeIngredientRepository; import server.database.RecipeRepository; @@ -34,16 +35,16 @@ public class RecipeController { private final RecipeRepository recipeRepository; // JPA repository used in this controller private final SimpMessagingTemplate messagingTemplate; private final RecipeIngredientRepository recipeIngredientRepository; - private final IngredientController ingredientController; + private final IngredientRepository ingredientRepository; public RecipeController(RecipeRepository recipeRepository, SimpMessagingTemplate messagingTemplate, - IngredientController ingredientController, + IngredientRepository ingredientRepository, RecipeIngredientRepository recipeIngredientRepository) { this.recipeRepository = recipeRepository; this.messagingTemplate = messagingTemplate; this.recipeIngredientRepository = recipeIngredientRepository; - this.ingredientController = ingredientController; + this.ingredientRepository = ingredientRepository; } /** @@ -80,7 +81,19 @@ public class RecipeController { return ResponseEntity.ok(recipeRepository.findAll()); } - + private Recipe saveRecipeAndDependencies(Recipe recipe) { + recipe.getIngredients() + .forEach(recipeIngredient -> + recipeIngredient.setIngredient( + ingredientRepository + .findByName(recipeIngredient.getIngredient().name) + .orElseGet(() -> ingredientRepository.save(recipeIngredient.getIngredient()) + )) + ); + recipeIngredientRepository.saveAll(recipe.getIngredients()); + Recipe saved = recipeRepository.save(recipe); + return saved; + } /** * Mapping for POST /recipe/{id}. * Also creates the ingredient elements if they do not exist. @@ -94,11 +107,7 @@ public class RecipeController { if (!recipeRepository.existsById(id)) { return ResponseEntity.badRequest().build(); } - recipe.getIngredients().stream() - .map(recipeIngredient -> recipeIngredient.ingredient) - .forEach(ingredientController::createIngredient); - recipeIngredientRepository.saveAll(recipe.getIngredients()); - Recipe saved = recipeRepository.save(recipe); + Recipe saved = saveRecipeAndDependencies(recipe); messagingTemplate.convertAndSend(Topics.RECIPES, new UpdateRecipeMessage(saved)); return ResponseEntity.ok(saved); @@ -128,12 +137,7 @@ public class RecipeController { if (recipeRepository.exists(Example.of(example))) { return ResponseEntity.badRequest().build(); } - // FIXME reduce code duplication - recipe.getIngredients().stream() - .map(recipeIngredient -> recipeIngredient.ingredient) - .forEach(ingredientController::createIngredient); - recipeIngredientRepository.saveAll(recipe.getIngredients()); - Recipe saved = recipeRepository.save(recipe); + Recipe saved = saveRecipeAndDependencies(recipe); messagingTemplate.convertAndSend(Topics.RECIPES, new CreateRecipeMessage(saved)); return ResponseEntity.ok(saved); diff --git a/server/src/main/java/server/database/IngredientRepository.java b/server/src/main/java/server/database/IngredientRepository.java index ea32d67..df54bd3 100644 --- a/server/src/main/java/server/database/IngredientRepository.java +++ b/server/src/main/java/server/database/IngredientRepository.java @@ -6,9 +6,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import java.util.Optional; public interface IngredientRepository extends JpaRepository { List findAllByOrderByNameAsc(); Page findAllByOrderByNameAsc(Pageable pageable); + Optional findByName(String name); }