#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:
Я идиот. Тип данных был неправильно задан в базе данных. Создание новой базы данных решило эту проблему.