简体   繁体   中英

How to perform an upsert on entity with JoinColumn in JPA and Hibernate

Fairly new to the hibernate-core integrate with JPA. Our entities look like

@MappedSuperclass
abstract class BasicEntity {

    @Id
    @GenericGenerator(name="uuid",strategy="uuid")
    @GeneratedValue(generator="uuid")
    private String id;

}

@Entity
@Table(name = "book")
class Book extends BasicEntity { 
    @ManyToOne
    @JoinColumn(name="book_genre")
    Genre genre

    @Column(name="texture")
    String texture;
}

@Data //lombok
@Entity
@Table(name="user_book_mapping")
class UserBookMapping extends BasicEntity {
    @ManyToOne
    @JoinColumn(name = "book_id")
    private Book book;
    
    @Column(name="user_id")
    String user_id;
}

What I am trying to perform is for every book read by a user, upsert (a book can be read twice by the same user) the UserBookMapping table. Request object includes an array of user and books [{userId, bookId}] attributes for me to process.

Currently I am stuck with a solution where I am ending up fetching the Book entity from the primary table first, then fetching if such a row already exists with a combination of userId+bookId and then creating a new instance of UserBookMapping to write it to the database.

This doesn't look optimized in any sense to me. Theoretically(and in the NoSql world), what should be sufficient for me to do all of this would be to ensure valid bookIds are requested ( EXISTS ) and then perform an UPSERT for the UserBookMapping . But I am puzzled with both the ways to write and to formulate the data as java objects while computing.

Q1. Do I really need to construct the Book entity?

Q2. What is the clean way to do what I am trying to achieve?

As was suggested by @crizzis, you can do something like this:

Book book = entityManager.getReference(Book.class, bookId);
Long booksPerUserCount = entityManager.createQuery(
    "select count(bu) from UserBookMapping bu where bu.book = :book and bu.user_id = :userId",
 Long.class )
.setParameter("book", book)
.setParameter("userId", userId)
.getSingleResult(); 

if (booksPerUserCount > 0) {
   UserBookMapping userBook = new UserBookMapping();
   userBook.setBook(book);
   userBook.setUserId(userId);
   entityManager.persist(userBook);
}

But it will work only if you know for sure that a book with id bookId exists. You can read about entityManager.getReference() in hibernate documentation .

Please also note that this is not good idea to use @Data lombok annotation in hibernate/jpa entity, see for example this article .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM