Невозможно сохранить ArrayList объектов в MySQL — Hibernate / Spring Boot

#java #mysql #spring-boot #hibernate #arraylist

#java #mysql #весенняя загрузка #спящий режим #массив

Вопрос:

У меня возникли некоторые проблемы с тем, что я считаю своим реляционным отображением в Hibernate. Это для приложения для хранения рецептов.

Первоначально в классе recipe было String ingredients поле, в котором хранились все ингредиенты. Мы поняли, что это не имеет смысла для хранения списка ингредиентов в рецепте, поэтому я нахожусь в процессе рефакторинга, чтобы он стал списком нового типа, который я создал, Ingredient : List<Ingredient> ingredients . Поле формы ингредиента динамически создается JS во внешнем интерфейсе и при отправке запроса POST преобразуется в массив новых ингредиентов, а затем добавляется в модель рецепта.

Всякий раз, когда он достигает строки, в которой он сохраняет его в базе данных, я получаю эту ошибку:

Field 'ingredients' doesn't have a default value , который сообщает мне, что поле равно нулю. Однако, когда я использую инструменты отладки, это показывает мне, что newRecipe.ingredients не равен null, на самом деле это ArrayList, созданный на основе данных во внешнем интерфейсе.

Класс ингредиентов выглядит следующим образом:

 @Entity
public class Ingredient extends AbstractEntity{

    @ManyToOne(targetEntity = Recipe.class,
            fetch = FetchType.LAZY,
            cascade = {CascadeType.MERGE, CascadeType.REMOVE})
    @NotNull(message = "Please include ingredients")
    private Recipe recipe;

    @Id
    @GeneratedValue
    private int id;

    private String ingredient;

    public Ingredient(String ingredient) {
        this.ingredient = ingredient;
    }

    public String getIngredient() {
        return ingredient;
    }

    public void setIngredient(String ingredient) {
        this.ingredient = ingredient;
    }

}
 

Класс Recipe находится здесь:

 @Entity
public class Recipe extends AbstractEntity {

   private String name;

   @OneToMany(mappedBy = "recipe")
   @NotNull(message = "Ingredients required")
   private List<Ingredient> ingredients = new ArrayList<Ingredient>();

   private String directions;

   @OneToMany(mappedBy = "recipe")
   private List<Instruction> instructions = new ArrayList<Instruction>();

   @NotNull(message = "Category required")
   private Category category;

   private Tag tag;

   private String img;

   @OneToMany(mappedBy = "recipe", cascade = {CascadeType.MERGE, CascadeType.REMOVE})
   @NotNull(message = "User is required")
   private List<UserRecipe> users = new ArrayList<>();

   public Recipe() {
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }


   public Category getCategory() {
      return category;
   }

   public void setCategory(Category category) {
      this.category = category;
   }

   public List<UserRecipe> getUsers() {
      return users;
   }

   public void setUsers(List<UserRecipe> users) {
      this.users = users;
   }

   public String getImg() {
      return img;
   }

   public void setImg(String img) {
      this.img = img;
   }


   public List<Ingredient> getIngredients() {
      return ingredients;
   }

   public void setIngredients(List<Ingredient> ingredients) {
      this.ingredients = ingredients;
   }

   public String getDirections() {
      return directions;
   }

   public void setDirections(String directions) {
      this.directions = directions;
   }

   public Tag getTag() {
      return tag;
   }

   public void setTag(Tag tag) {
      this.tag = tag;
   }

   public List<Instruction> getInstructions() {
      return instructions;
   }

   public void setInstructions(List<Instruction> instructions) {
      this.instructions = instructions;
   }
}
 

RecipeController здесь:

 @PostMapping("create")
   public String createRecipe(HttpServletRequest request, @ModelAttribute Recipe newRecipe,
                              @ModelAttribute @Valid String newCategory,
                              Errors errors, Model model, RedirectAttributes redirectAttrs) {

      if (errors.hasErrors()) {
         model.addAttribute("title", "Create Recipe");
         return "recipes/create";
      }

      String[] ingredients = request.getParameterValues("ingredient");

      List<Ingredient> ingredientsList = new ArrayList<Ingredient>();

      for (int i = 0; i < ingredients.length; i  ) {
         Ingredient newIngredient = new Ingredient(ingredients[i]);
         ingredientsList.add(newIngredient);
      }
      newRecipe.setIngredients(ingredientsList);
      
      // THIS PRINTS AN ARRAY OF THE NUMBER OF INGREDIENTS ADDED
      System.out.println(ingredientsList.toString());

      // HERE IS WHERE MY ERROR HAPPENS
      Recipe recipe = recipeRepository.save(newRecipe);
      redirectAttrs.addAttribute("recipeId", recipe.getId());

      return "redirect:/recipes/display";
   }
 

Моя мысль здесь заключается в том, что я каким-то образом неправильно сопоставляю список ингредиентов с рецептом, но я не могу понять это, и после 3 дней поиска в Google и устранения неполадок я здесь. Любая помощь будет с благодарностью принята. Заранее спасибо!

Ответ №1:

Это может быть проблемой схемы в вашей базе данных. Вы создали свою схему вручную или используете auto-ddl? Если вы создали его вручную, возможно, вам не хватает столбца recipe_id в таблице Ингредиентов. Если такой объединенный столбец имеет другое имя, вы должны переопределить его с помощью @JoinColumn в классе ингредиентов следующим образом:

 @ManyToOne(targetEntity = Recipe.class,
            fetch = FetchType.LAZY,
            cascade = {CascadeType.MERGE, CascadeType.REMOVE})
    @NotNull(message = "Please include ingredients")
    @JoinColumn("the_recipe_id") // **** Here you put the join column name you specified **** //
    private Recipe recipe;

 

РЕДАКТИРОВАТЬ: Кроме того, можете ли вы опубликовать свой класс AbstractEntity? Проблема также может быть связана с отсутствием ключа в классе Recipe.

Комментарии:

1. Спасибо, Сантьяго. Это определенно была проблема с БД — я, к сожалению, не изменил тип данных ingredient . Создание новой базы данных решило эту проблему.

2. Рад это слышать! Приветствия!

Ответ №2:

Я идиот. Тип данных был неправильно задан в базе данных. Создание новой базы данных решило эту проблему.