The requirement is to create a dynamic form which will allow user to add dynamic INGREDIENTS of a RECIPE. Issue is that when users try to add more than 1 INGREDIENT, Hibernate is throwing error. I am unable to resolve this error. I checked the multiple post like link 1, link 2 etc but that doesn't help.
Oracle table
create table ingredient(ingredient_id number(4) primary key,
quantity varchar2(20),
ingredient varchar2(40));
create table recipe(id number primary key,
name varchar2(25) unique,
ingredient_id number(4),
constraint ingredient_fk foreign key(ingredient_id)
references ingredient(ingredient_id));
Ingredient and Recipe POJO
@Entity
@Table(name = "ingredient")
public class Ingredient implements Serializable {
private static final long serialVersionUID = -2489479702169761646L;
@Id
@Column(name = "ingredient_id")
private Integer id;
@Column(name = "quantity")
private String quantity;
@Column(name = "ingredient")
private String ingredient;
//getter and setters
}
@Entity
@Table(name = "recipe")
public class Recipe implements Serializable {
private static final long serialVersionUID = 4398676897855994030L;
@Id
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name = "ingredient_id")
private List<Ingredient> ingredients;
//getters and setter
}
MVC
@RequestMapping("/add")
public String newRecipe(Model model) {
Recipe recipe = new Recipe();
recipe.setIngredients(new AutoPopulatingList<Ingredient>(Ingredient.class));
model.addAttribute("recipe", recipe);
return "recipes/new";
}
@RequestMapping(value = "add", method = RequestMethod.POST)
public String addRecipe(@Valid Recipe recipe, BindingResult result,
Model model) {
if (result.hasErrors()) {
return "recipes/new";
}
recipeServices.addRecipe(recipe);
return "redirect:/recipe/" + recipe.getId();
}
**DAO code which is called from recipeServices **
public class RecipeDaoImpl implements RecipeDao {
public void addRecipe(Recipe recipe) {
//Set the id of recipe and ingredient.
recipe.setId(getNext());
List<Ingredient> ingredients = recipe.getIngredients();
for (Ingredient ingredient : ingredients) {
ingredient.setId(getNext());
}
getSession().save(recipe);
}
}
JSP code
<html>
<script type="text/javascript">
<!--
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "checkbox";
element1.name = "chkbox[]";
cell1.appendChild(element1);
var length = rowCount - 1;
var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
element2.name = "ingredients[" + length + "].quantity";
cell2.appendChild(element2);
var cell3 = row.insertCell(2);
var element3 = document.createElement("input");
element3.type = "text";
element3.name = "ingredients[" + length + "].ingredient";
cell3.appendChild(element3);
var cell4 = row.insertCell(3);
var element4 = document.createElement("input");
element4.type = "text";
element4.name = "ingredients[" + length + "].comments";
cell4.appendChild(element4);
}
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
if (null != chkbox && true == chkbox.checked) {
table.deleteRow(i);
rowCount--;
i--;
}
}
} catch (e) {
alert(e);
}
}
-->
</script>
</head>
<body>
<s:url value="/recipe/add" var="recipe_new" />
<sf:form modelAttribute="recipe" action="${recipe_new}" method="POST">
<table>
<tr>
<th align="left" valign="middle">Recipe Name:</th>
<td colspan="2"><sf:input path="name" id="recipeName" /> <br />
<sf:errors path="name" cssClass="error" /></td>
</tr>
<tr>
<td>
<h3>Ingredients</h3> <INPUT type="button" value="+"
onclick="addRow('dataTable')" /> <INPUT type="button" value="-"
onclick="deleteRow('dataTable')" />
<table id="dataTable" width="350px" border="1">
<tr>
<th></th>
<th>Quantity</th>
<th>Ingredient</th>
</tr>
<tr>
<td><input type="checkbox" name="chk" /></td>
<td><sf:input type="text" path="ingredients[0].quantity"
title="Quantity" placeholder="Quantity" /></td>
<td><sf:input type="text" path="ingredients[0].ingredient"
title="Ingredient" placeholder="Ingredient" /></td>
</tr>
</table>
</td>
</tr>
</table>
</sf:form>
</body>
</html>
Error At front end JSP page, below the Recipe name I am getting error : "Already recipe with same name exists. Choose different recipe name."
Following is passed from JSP (The DAO code populate the recipe_id and ingredient_ids) Received from JSP [Recipe [id=41, name=Sandwich, ingredients=[Ingredient [ingredient_id=42, quantity=250gm, ingredient=Salt], Ingredient [ingredient_id=43, quantity=250gm, ingredient=Pepper powder]]]
Exception: could not retrieve snapshot: [com.recipe.tables.Ingredient#42]
org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
org.hibernate.persister.entity.AbstractEntityPersister.getDatabaseSnapshot(AbstractEntityPersister.java:1137)
Can you please suggest how to resolve this?
Thanks in advance :) :)