简体   繁体   中英

How do I return only two fields from two separate tables using Hibernate?

How would I return the following JSON using the classes below, without returning userId and bookId ? I have tried various different queries and none yield the desire result. It doesn't have to match the json names exactly. I just want a username and a list of books to be returned.

Please refer to Repository @Query

{
   "userName": "jamesbond007",
   "books": [
       "Cat In the Hat",
       "Green Eggs and Ham
   ]
}

Users.java:

@Getter
@Entity
@Table(name = "users")
public class User {
    @Id
    @OneToMany
    @JoinColumn(name = "user_id")
    private Integer userId;
    
   @Column(name = "user_name")
    private String userName;
}

Books.java:

@Getter
@Entity
@Table(name = "books")
public class Books {
    @Id
    @OneToMany
    @JoinColumn(name = "book_id") 
    private Integer bookId;

    @Column(name = "book_name")
    private String bookName;
}

UserBooks.java:

@Getter
@Entity
@Table(name = "user_books")
public class UserBooks{
    @Id
    @Column(name = "user_book_id")
    private Integer userBookId;
    
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user
    
    @ManyToOne
    @JoinColumn(name = "book_id")
    private Book book;
}

Repository:

public interface MyRepository extends JPARepository<UserBooks, Integer> {
     @Query("SELECT ub.userName, ub.bookName FROM UserBooks ub JOIN ub.User JOIN ub.Book WHERE userId=?1") //WHAT DO I DO HERE?
     UserBooks getAllBooksByUser(Integer userId);
}

I would make two queries. One to fetch the User's Username and the other to fetch all the books from him. Then I would create a DTO (Data Transfer Object) that keeps only the data that I need.

eg:

public class MyDto
{
    String username;
    
    List<Books> booksList;
    
    // Getters Setters

}

Then implement the Repo to get all the books for this user:

public interface BookRepo extends JPARepository<Books, Integer> {
     @Query("SELECT b.* FROM User_books ub JOIN User ON u.user_id = ub.user_id JOIN Book b ON ub.book_id = b.book_id WHERE u.user_id=?1", nativeQuery = true) 
     List<Books> getAllBooksByUserId(Integer userId);
}

And a simple scenario on a service would be:

    getUsernameAndBooks(int userId)
    {
        User user = userRepo.findById(userId);

        List<Books> booksList = bookRepository.getAllBooksByUserId(userId);
        
        return new MyDto(user.getUsername(), booksList)
    }

Something is wrong with your mapping and it's not clear if you have bidirectional or unidirectional associations. Note that you can get the info you need in both cases but the query changes a bit.

Because you've tried to use the @OneToMany annotation, I will assume that you are trying to create a bidirectional association:

    @Entity
    @Table(name = "users")
    public class User {
        @Id
        @Column(name = "user_id")
        private Integer userId;

        @Column(name = "user_name")
        private String userName;
        
        @OneToMany(mappedBy="user")
        private Set<UserBooks> books = new HashSet<>();
    }

    @Entity
    @Table(name = "books")
    public class Book {
        @Id
        @Column(name = "book_id")
        private Integer bookId;

        @Column(name = "book_name")
        private String bookName;
        
        @OneToMany(mappedBy="book")
        private Set<UserBooks> users = new HashSet<>();
    
    }

    @Entity
    @Table(name = "user_books")
    public class UserBooks{
        @Id
        @Column(name = "user_book_id")
        public Integer userBookId;

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

        @ManyToOne
        @JoinColumn(name = "book_id")
        private Book book;
    }

Nou can get all the information you need with:

public interface MyRepository extends JPARepository<User, Integer> {
     @Query("SELECT u FROM User u JOIN FETCH u.books ub JOIN FETCH ub.book b WHERE u.userId=?1")
     User getAllBooksByUser(Integer userId);
}

And get the info you need with:

User user = getAllBooksByUser(...);
String userName = user.getUserName();
List<String> bookNames = user.getUserBooks().stream()
                           .map(userBook -> userBook.getBook().getBookName())
                           .collect(Collectors.toList());  

You could also use @ManyToMany and remove UserBooks :

    @Entity
    @Table(name = "users")
    public class User {
        @Id
        @Column(name = "user_id")
        private Integer userId;

        @Column(name = "user_name")
        private String userName;
        
        @ManyToMany
        private Set<Book> books = new HashSet<>();
    }

    @Entity
    @Table(name = "books")
    public class Book {
        @Id
        @Column(name = "book_id")
        private Integer bookId;

        @Column(name = "book_name")
        private String bookName;
        
        @ManyToMany
        private Set<User> users = new HashSet<>();
    
    }

and the query would become:

public interface MyRepository extends JPARepository<User, Integer> {
     @Query("FROM User u JOIN FETCH u.books WHERE u.userId=?1")
     User getAllBooksByUser(Integer userId);
}

I will just leave you to the Hibernate ORM documentation section with all the details about it.

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