У меня есть 2 класса сущностей: "Menu"
, в котором есть только одно поле с именем "name"
, и вторая сущность - "Ingredients"
, в которой есть 2 поля - "ingredientName"
и "ingredientDescription"
. Структура базы данных
Я создаю простое веб-приложение CRUD, но метод обновления вместо обновления сущности вставляет новые значения в БД. Я проверил, и когда пользователь нажимает на обновление в указанном меню , у первого субъекта id и его идентификаторов ингредиентов также предопределены. Я новичок в Spring Boot и Thimeleaf и не знаю, как работать с JPA, когда у вас более 1 сущности.
Элемент меню:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
@Column(name = "name")
private String name;
// Mapping To second table
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "menu_ingredient",
joinColumns = @JoinColumn(name = "menu_id"),
inverseJoinColumns = @JoinColumn(name = "ingredient_id"))
private List<Ingredients> ingredient = new ArrayList<>();
//Getters/Setters/Constructors/ToString
Состав субъекта:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "ingredient")
private String ingredientName;
@Column(name = "description")
private String ingredientDescription;
//Getters/Setters/Constructors/ToString
Контроллер (только методы обновления):
@GetMapping("/edit/{id}")
public String edit(@PathVariable(name = "id")String id, Model model){
Optional<Menu> menu = menuRepository.findById(id);
List<Ingredients> ingredients = menu.get().getIngredient();
for (Ingredients ing : ingredients){
System.out.println(ing);
}
model.addAttribute("ingredients", ingredients);
model.addAttribute("newMenu",menu);
return "edit-page";
}
@PostMapping("/postEditMenu")
public String postEdit(@ModelAttribute("newMenu")Menu menu){
menuRepository.save(menu);
return "redirect:/recipeList";
}
edit-page.html:
<form action = "#" th:action="@{/postEditMenu}" th:object="${newMenu}" method="post">
<p>Menu Name: <br><input type="text" th:field="*{name}"></p>
<div id="wrapper" th:each="ing: ${ingredients}">
<label for="ingredientName"></label>
<p>Ingredient Name: <br><input th:value="${ing.ingredientName}" id="ingredientName" type="text" name="ingName"></p>
<label for="ingredientDescription"></label>
<p>Ingredient Description:</p> <textarea id="ingredientDescription" type="text" th:text="${ing.ingredientDescription}" name="ingDesc"></textarea>
</div>
<br>
<input type="button" id="more_fields" onclick="add_fields();" value="Add More" />
<br>
<input type="submit" th:value="Submit">
</form>
FIX Я на самом деле понял это с помощью ответов ниже. Вот код:
@PostMapping("/postEditMenu")
public String postEdit(@ModelAttribute("newMenu")Menu menu,
@RequestParam String ingName,
@RequestParam String ingDesc){
String[] ingNameSplit = ingName.split(",");
String[] ingDescSplit = ingDesc.split(",");
Menu menuToUpdate = menuRepository.getOne(menu.getId());
List<Ingredients> newIngredientList = menuToUpdate.getIngredient();
newIngredientList.clear();
for(int a = 0, b = 0; a<ingNameSplit.length; b++, a++){
newIngredientList.add(new Ingredients(ingNameSplit[a], ingDescSplit[b]));
}
menuToUpdate.setIngredient(newIngredientList);
menuRepository.save(menuToUpdate);
return "redirect:/recipeList";
}
Итак, сначала я добавил скрытые поля "id" для каждого необходимого элемента, например:
<input type="text" th:field = "*{id}" hidden>
и
<input type="text" th:value = "${ing.id}" hidden>
Затем в методе postEditMenu
я добавил @RequestParam String ingName,
и @RequestParam String ingDesc
, чтобы получить ввод новых элементов из тимилиста, затем разделил эту строку и добавил ее в массив String [] с помощью String[] ingNameSplit = ingName.split(",")
, поскольку input будет одной большой строкой, разделенной запятыми, а не array []. Затем я получаю меню, которое пользователь хочет обновить - Menu menuToUpdate = menuRepository.getOne(menu.getId());
menu.getId()
не является нулевым, потому что я установил скрытые поля "id" в тимелист. Затем я получаю ингредиенты этого меню - List<Ingredients> newIngredientList = menuToUpdate.getIngredient();
, потому что список уже будет заполнен существующими ингредиентами. Я очищаю этот список и добавляю новые ингредиенты, которыми пользователь заполнит форму -
for(int a = 0, b = 0; a<ingNameSplit.length; b++, a++){
newIngredientList.add(new Ingredients(ingNameSplit[a], ingDescSplit[b]));
}
после этого я установил newIngredientsList
и сохранил само меню в БД -
menuToUpdate.setIngredient(newIngredientList);
menuRepository.save(menuToUpdate);
Спасибо за помощь, ребята:)