javaspringspring-bootspring-data-jpa

One to Many relationship, update data in spring boot is not working


iam a naive user, working on Spring boot., Creating a onetoMany relationship with User(Parent) - > Address(Child).

POST is working ( Creating a user is working)

Unable to update the User Record on Postman, tried to search online but none of the solutions worked for me.

here is my code

User.java

@Entity
public class User {

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

    private String name;
   // @JsonIgnore
    @JsonManagedReference
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Address> addresses;

    // Getters and setters
}

@Entity
public class Address {

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


    private String street;
    private String city;
    private String state;
    private String zip;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    // Getters and setters
}

UserController.java

   @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        User existingUser = userService.getUser(id);
        existingUser.setName(user.getName());
        existingUser.setAddresses(user.getAddresses());
        return userService.updateUser(existingUser);
    }


userService.java

    public User updateUser(User user) {
        return userRepository.save(user);
    }

**OutPut**


org.hibernate.TransientObjectException: persistent instance references an unsaved transient instance of 'com.clt.product_service.entity.User' (save the transient instance before flushing)
    at org.hibernate.engine.spi.CascadingActions$9.cascade(CascadingActions.java:382) ~[hibernate-core-6.6.4.Final.jar:6.6.4.Final]
    at org.hibernate.engine.spi.CascadingActions$9.cascade(CascadingActions.java:372) ~[hibernate-core-6.6.4.Final.jar:6.6.4.Final]
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:570) ~[hibernate-core-6.6.4.Final.jar:6.6.4.Final]
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:492) ~[hibernate-core-6.6.4.Final.jar:6.6.4.Final]

Postman - Output

 "timestamp": "2025-02-20T20:35:11.402+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: persistent instance references an unsaved transient instance of 'com.clt.product_service.entity.User' (save the transient instance before flushing)\r\n\tat org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:368)\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.

Updated the Code as Suggested below

public User updateUser(@PathVariable Long id, @RequestBody User user) {
    User existingUser = userService.getUser(id);
    existingUser.setName(user.getName());
     existingUser.setAddresses(user.getAddresses().stream()
            .map(address -> {
                address.setId(null);
                address.setUser(existingUser);
                return address;
            })
            .toList());
  return userService.updateUser(existingUser);
}

now getting error as

"timestamp": "2025-02-21T03:47:47.749+00:00", "status": 500, "error": "Internal Server Error", "trace": "java.lang.UnsupportedOperationException\r\n\tat java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)\r\n\tat java.base/java.util.ImmutableCollections$AbstractImmutableCollection.clear(ImmutableCollections.java:149)\r\n\tat org.hibernate.type.CollectionType.replaceElements(CollectionType.java:506)\r\n\tat org.hibernate.type.


Solution

  • I believe the issue lies in the fact that you're using toList(), which returns an immutable list instead of mutable list. Could you change:

    .toList()
    

    to:

    .collect(Collectors.toList())