Issue
I know that there are many question about this topic, however I could not solve my problem even adding the CascadeType.ALL
.
I have a two tables called UserMenu and MenuItem (there are one-to-many relationship)
- UserMenuDTO:
@Entity
@Table(...)
@EntityListeners(AuditableListener.class)
public class UserMenuDTO implements Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column("...")
@NotBlank
private String name;
@OneToMany(mappedBy = "userMenuDTO", cascade = CascadeType.ALL, orphanRemoval=true)
private List<MenuItemDTO> menus = new ArrayList<>();
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn("..." )
private QrCodeDTO qrCodeDTO;
@ManyToOne
@JoinColumn("...")
private UserDTO userDTO;
- MenuItemDTO:
@Entity
@Table("...")
@EntityListeners(AuditableListener.class)
public class MenuItemDTO implements Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// ...
@Column("...")
@NotBlank
@Size(max = 100)
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "...")
private MenuPriceDTO menuPriceDTO;
@ManyToOne
@JoinColumn(name = "...")
private UserMenuDTO userMenuDTO;
- Here is the code where I am adding the menuitem to usermenu:
public static void addMenuItemToUserMenu(UserMenuDTO userMenuDTO, MenuItemDTO menuItemDTO){
userMenuDTO.getMenus().add(menuItemDTO);
menuItemDTO.setUserMenuDTO(userMenuDTO);
}
- When I am inserting new menu item to userMenu list, I am getting this error:(cascadeType.ALL has no effect)
InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException:
object references an unsaved transient instance -
save the transient instance before flushing: ...MenuItemDTO;
If I save the MenuItem just before the saving the userMenu, everything is fine. I just want to save all items in one statement.
How can i solve this issue?
- Update (details for persist operation)
public void persist(){
UserMenuDTO userMenuDTO = ; // this is from database via userid;
MenuItemDTO newMenuItemDTO=; // created from request body
Relation.addMenuItemToUserMenu(userMenuDTO, newMenuItemDTO);
userService.saveUserMenuDTO(userMenuDTO);
}
@Service
@Transactional
public class UserService{
@Override
public void saveUserMenuDTO(UserMenuDTO userMenuDTO) {
userMenuRepository.save(userMenuDTO);
}
}
@Repository
public interface UserMenuRepository extends JpaRepository<UserMenuDTO, Long> {
}
Solution
If you see your persist
method, the problem is with new menuItem
object, as it is not attached to the persistence context (in other words it is transient) and you are assigning this transient object to an existing userMenuDTO
instance fetched from database, this instance fetched from database is attached to the current spring persistence context. So in order to update the list of menus
of this already persisted object you have to persist the newly created menuItem
first, then add this persisted menuItem
to the menus
list and then finally save the userMenuDTO
.
CascadeType.ALL
would work if both the userMenuDTO
and menuItemDTO
instances were newly created and you were saving them to database for the first time.
Answered By - Naqi