Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java

Updating object through CRUD-Repository`s save method changes it's ID.

I am currently working on the last project of the Java Web Dev Techdegree. There is a Recipe object which I edit through a Thymeleaf form and then save it using a CRUD repository. The id entry in the database is 1 and the id of the incoming object is 1, too. After saving the former object is not updated but the id is incremented.

recipe // Recipe with id=1
save(recipe)
recipe // Now has id=2

Does someone have an idea what's going on here?

2 Answers

Hi,

I was able to save problem partially. Was inspired by solution here

http://stackoverflow.com/questions/27673615/spring-data-jpa-inserting-instead-of-update

The problem is in @Version version field. I was not able to understand 100% why it is so, but @Version field id like @Id field. So here is how I solved your problem:

I. Put hidden input with version in your index.html:

<input type="hidden" th:field="*{version}"/>

II. I don't know a workaround yet, but let @Id id field in BaseEntity be NOT final, and add both getters and setters fort @Version version and @Id id fields.

This way Thymeleaf will set recipe.id and recipe.version using hidden fields and your RecipeRepository will know that your Recipe exists. Well that is how I roughly see it right now.

I'll post my changed BaseEntity class that worked. Let me know if that worked for you.

@MappedSuperclass
public class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private Long version;

    // Getters and Setters

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Long getVersion() {
        return version;
    }
    public void setVersion(Long version) {
        this.version = version;
    }

    // constructor
    public BaseEntity() {
        id = null;
    }

}

I also removed equals and hashCode fields. I don't know why do you need them...

Anyway I just wanted to give you working version of your code. I was able to update 'Ham and Eggs'. And you can start playing around to introduce new code...

So let me know if it worked

Awesome! Thank you very much I fiddled around with the non-final id field before but didn't think of the version field.

Hi,

I tried to download your project from GitHub, it runs, but I don't know how to reproduce error.

So I the only method in RecipeController that is updating recipe is this setFavorite. I tried to print recipe id before and after :

    @RequestMapping("/recipe/{id}/favorite")
    public String setFavorite(@PathVariable Long id, Model model) {
        Recipe recipe = recipeService.findById(id);
        recipe.setFavorite(!recipe.isFavorite());
        System.out.println("before " + recipe + " "  + recipe.getId());
        recipeService.save(recipe);
        System.out.println("after " + recipe + " "  + recipe.getId());
        return String.format("redirect:/recipe/%s", id);
    }

Then when I opened browser and made request as your controller suggests:

http://localhost:8080/recipe/1/favorite

Both id after and before are the same.

So maybe you didn't push the new code?

The problem is obvious: Spring is trying to save new entry instead of updating the old one ...

And the solution should depend on your project...

So again, to figure out what is going on, I need you to show me where the error is.

Also it seems you didn't add CSS files to your GitHub repo.

Hey Alexander my code is a bit messy as it is in production right now. I've just added CSS and IMGs and pushed the new code for you. The problem is on line 64 of the RecipeController. Try to edit the first recipe. The problem is that on line 64 there, it is not updating the existing recipe but is creating a new one.

Thank you for the support.

So I did the following: printed id before and after save in here:

    @RequestMapping(value = "/index", method = RequestMethod.POST)
    public String addRecipe(@Valid Recipe recipe, BindingResult result,
                            @RequestParam(name = "item") String item,
                            @RequestParam(name = "condition") String condition,
                            @RequestParam(name = "quantity") String quantity,
                            HttpServletRequest request
            ) {

        String[] items = item.split(",");
        String[] conditions = condition.split(",");
        String[] quantities = quantity.split(",");

        List<Ingredient> ingredients = new ArrayList<>();
        for (int i = 0; i < items.length; i++) {
            ingredients.add(
                    new Ingredient(
                            items[i],
                            conditions[i],
                            Integer.parseInt(quantities[i]))
            );
        }
        recipe.setIngredients(ingredients);
        System.out.println("recipe before " + recipe + " , id =" + recipe.getId());
        recipeService.save(recipe);
        System.out.println("recipe after " + recipe + " , id =" + recipe.getId());
        return "redirect:/index";
    }

then I went for 1-st recipe and edited it, and you are right. Somehow your id is null, That what I was given:

recipe before com.floriantoenjes.recipe.Recipe@0 , id =null
recipe after com.floriantoenjes.recipe.Recipe@3e , id =2

Problem is confirmed. Trying to solve...