monstereo
monstereo

Reputation: 948

object references an unsaved transient even using CascadeType.All

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)

@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;
@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;
public static void addMenuItemToUserMenu(UserMenuDTO userMenuDTO, MenuItemDTO menuItemDTO){
        userMenuDTO.getMenus().add(menuItemDTO);
        menuItemDTO.setUserMenuDTO(userMenuDTO);
    }
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?

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> {
}

Upvotes: 0

Views: 190

Answers (1)

Naqi
Naqi

Reputation: 252

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.

Upvotes: 1

Related Questions