1

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 :) :)

Community
  • 1
  • 1
user92161
  • 107
  • 2
  • 8
  • Can you please post `addRecipe` code where you are actually inserting entries into database? – Rohan Nov 24 '14 at 09:30
  • @RRR: Have updated the post.. the code is actually calling getSession().save(ObjectName) – user92161 Nov 24 '14 at 09:45
  • Do you already have recipe with name `Sandwich` in db? – Rohan Nov 24 '14 at 09:54
  • @RRR: No. There are no records in Recipe or Ingredient table. I believe for some reason Hibernate is trying to insert the same row twice in Recipe table. The mapping of Recipe and Ingredient looks ok to me therefore, I am not sure why this error is occurring. – user92161 Nov 24 '14 at 10:06

0 Answers0