Home > Enterprise >  Not-null property references a null or transient value when delete entity with many relations
Not-null property references a null or transient value when delete entity with many relations

Time:05-25

I have AppUser that can have many BookCards, which can have many Books. I need to delete my AppUser with his BookCards entities, but no change for the book itself. But when I tried do it by this method

@Transactional
    public void deleteUser(Long id) {
        List<BookCard> bookCards = bookCardService.findAllUserBookCards(id);

        if (!bookCards.isEmpty()) {
            bookCardService.deleteBookCardByUserId(id);
        }

        userRepository.deleteById(id);
    }

I got an error

org.hibernate.PropertyValueException: not-null property references a null or transient value : kpi.diploma.ovcharenko.entity.card.BookCard.book

This are my AppUser, Book And BookCard classes

@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "email"), name = "library_user")
public class AppUser {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    // other fields 

    @EqualsAndHashCode.Exclude
    @OnDelete(action = OnDeleteAction.CASCADE)
    @OneToMany(mappedBy = "book", fetch = FetchType.EAGER)
    private Set<BookCard> bookCards = new HashSet<>();

    // getters and setters
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(name = "booking_card")
@TypeDef(
        name = "pgsql_enum",
        typeClass = PostgreSQLEnumType.class
)
public class BookCard {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JoinColumn(name = "user_id", nullable = false)
    private AppUser user;

    @OnDelete(action = OnDeleteAction.NO_ACTION)
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "book_id")
    private Book book;

    // getters and setters
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(name = "books")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idbooks", insertable = false, updatable = false)
    private Long id;

    // other fields 

    @EqualsAndHashCode.Exclude
    @OnDelete(action = OnDeleteAction.NO_ACTION)
    @OneToMany(mappedBy = "book", fetch = FetchType.EAGER)
    private Set<BookCard> bookCards = new HashSet<>();
    
    // getters and setters

As you can see, my Book class has field of Set bookCards, its just for understating that I tried to add many annotations, like @OnDelete(action = OnDeleteAction.CASCADE), believe that them can solve my problem

As I understand, its no problem with deleteting AppUser and his BookCard, but because BookCard has a relation to the Book, hibernate doesn't understand what to do with the Book. So how can I make it clear to my program that I just need to delete BookCards enetities, but do not touch the book itself? Thank you very much

CodePudding user response:

For the future readers, who can face a similar error. I solve my problem changing entities like this

@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "email"), name = "library_user")
public class AppUser {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    // other fields 

    @EqualsAndHashCode.Exclude
    @OnDelete(action = OnDeleteAction.CASCADE)
    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<BookCard> bookCards = new HashSet<>();

    // getters and setters
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(name = "booking_card")
@TypeDef(
        name = "pgsql_enum",
        typeClass = PostgreSQLEnumType.class
)
public class BookCard {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id", nullable = false)
    private AppUser user;

    @ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
    @JoinColumn(name = "book_id")
    private Book book;

    // getters and setters
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(name = "books")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idbooks", insertable = false, updatable = false)
    private Long id;

    // other fields 

    @EqualsAndHashCode.Exclude
    @OnDelete(action = OnDeleteAction.CASCADE)
    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<BookCard> bookCards = new HashSet<>();
    
    // getters and setters

This annotation solve this problem org.hibernate.PropertyValueException: not-null property references a null or transient value : kpi.diploma.ovcharenko.entity.card.BookCard.book

  • Related