【问题标题】:How to use inner join with Spring MVC如何在 Spring MVC 中使用内连接
【发布时间】:2020-10-12 13:57:53
【问题描述】:

您好,我在外键和链接表之间编写了内部连接,但我无法打印第二个表中的数据。我在 Javascript 中遇到错误,可能第二个表中的数据没有出现。我需要用户表中的用户名,但我无法访问。

图书控制器

@Autowired
    private BooksService booksService;
    @Autowired
    private BookCommentsService bookCommentsService;

@RequestMapping(value = "/bookdetail")
    public ModelAndView showBookDetailForm(@RequestParam long book_id)
    {
        ModelAndView mav= new ModelAndView("bookdetail");
        List<Books> book=booksService.bookGetWithId(book_id);
        List<BookComments> listBookComments= bookCommentsService.listAllDetailComments(book_id);
        mav.addObject("listBook",book);
        mav.addObject("listBookComments", listBookComments);
        return mav;
    }

BookCommentsService

@Service
public class BookCommentsService {
    @Autowired
    private BookCommentsRepository repository;
    
    public List<BookComments> listAllDetailComments(long book_id)
    {
        return repository.listAllDetailComments(book_id);
    }
}

BookCommentsRepository

public interface BookCommentsRepository extends CrudRepository<BookComments, Long> {
    @Query(value = "Select b From BookComments b inner join Users u on b.comment_user_id = u.user_id where b.comment_book_id= :book_id")
    public List<BookComments> listAllDetailComments(@Param("book_id") long book_id);    
}

BookDetail.js

<c:forEach items="${listBookComments}" var="bookcomments">  
       (No problem here)    ${bookcomments.book_comment}        
       (The error is here) <h4>${bookcomments.user_name}</h4>                        
                </c:forEach>

【问题讨论】:

    标签: java mysql spring hibernate spring-mvc


    【解决方案1】:

    您应该使用comment_user_id 并关闭大括号,${bookcmets.comment_user_id} 应该可以正常工作。

    【讨论】:

    • 抱歉复制粘贴问题。我改变了它,但不再工作了。我可以访问 bookcmets.comment_user_id 但我需要 bookcmets.comment_user_name(user_name 在 Users 表中),BookComments 表没有 user_name 列,我使用内部联接但我无法访问 Users 表中的 user_name。
    【解决方案2】:

    要解决您的问题,您必须使用另一个对象(称为数据传输对象;DTO),其中将包含 BookComments 中的详细信息和用户名。

    一个例子是:

    package com.myapp.book;
    
    public class BookCommentsDto{
        private String bookComment;
        private String username;
        // You can add any other attributes that you need from the table book_comments
        // add them in the constructor as well
    
        public BookCommentsDto(String bookComment, String username){
             this.bookComment = bookComment;
             this.username = username;
        }
    }
    

    我将BookCommentsDto 类称为 dto。上面的 dto 是您可能需要的简单 dto。您可以从 dto 中的书评中添加您需要的其他详细信息,并确保也将它们添加到构造函数中。我在顶部包含了一个虚拟包名称,因为我们需要在我们将编写的查询中提及 dto 的完整类路径。在下面的查询中,我从 sql 的结果创建 dto。在查询中,我使用BookCommentsDto 的构造函数来创建将返回的对象。

    @Query(value = "Select new com.myapp.book.BookCommentsDto(b.book_comment, u.user_name) From BookComments b inner join Users u on b.comment_user_id = u.user_id where b.comment_book_id= :book_id")
    public List<BookCommentsDto> listAllDetailComments(@Param("book_id") long book_id);
    

    更新服务 BookCommentsService 中的返回类型

    @Service
    public class BookCommentsService {
        @Autowired
        private BookCommentsRepository repository;
        
        public List<BookCommentsDto> listAllDetailComments(long book_id)
        {
            return repository.listAllDetailComments(book_id);
        }
    }
    

    更新控制器

    @RequestMapping(value = "/bookdetail")
        public ModelAndView showBookDetailForm(@RequestParam long book_id)
        {
            ModelAndView mav= new ModelAndView("bookdetail");
            List<Books> book=booksService.bookGetWithId(book_id);
            List<BookCommentsDto> listBookCommentsDto= bookCommentsService.listAllDetailComments(book_id);
            mav.addObject("listBook",book);
            mav.addObject("listBookCommentsDto", listBookCommentsDto);
            return mav;
        }
    

    终于更新js

    <c:forEach items="${listBookCommentsDto}" var="bookcommentsDto">  
           ${bookcommentsDto.bookComment}        
           <h4>${bookcommentsDto.username}</h4>                        
    </c:forEach>
    

    如果您进行上述更改,代码应该可以正常工作。

    如果你想改进你的代码并在编码方面做得更好,我有几个 cmets 给你。 使用 Hibernate 时,我们必须考虑实体而不是数据库中的表。因此,我们不像在原生 sql 中那样进行内部连接,而是使用休眠关系来定义表之间的关系,并加入 entities 而不是表。在加入实体时,您可以阅读 OneToMany、ManyToOne 和 ManyToMany 关系。

    List&lt;Books&gt; book=booksService.bookGetWithId(book_id); book_id 正在返回 Books 的列表? book_id 应该是每本书唯一的,如果 id 使用正确,即使它返回一个书籍列表,列表的通用应该是 Book,而不是 BooksList&lt;Book&gt;,不是List&lt;Books&gt;

    当 hibernate 正确实现时,您应该能够一次检索所有数据,它会是这样的:

    这是您在使用 hibernate 一段时间(大约 1 年)后应该能够实现的代码类型,但是仍然有很多可以改进的地方。

    在书的存储库中

    @Query("from book b inner join b.comments c inner join c.users where b.book_id = :book_id")
    Book getBook(@Param("book_id") long book_id); // bookService.getBook will call this method
    

    控制器级别

    Book book = bookService.getBook(bookId); // only this one is querying the DB
    List<BookComment> bookComments = book.getComments();
    List<User> users = book.getComments().getUsers();
    

    要继续阅读的高级主题(按照发布的顺序阅读):

    1. HQL - 休眠查询语言
    2. Hibernate 的 N+1 问题
    3. JPA 规范(用于创建动态查询)
    4. QueryDsl - JPA 规范的改进

    【讨论】:

    • 非常感谢。我是 Java、spring 和 hibernate 的新手。编辑代码真的很棒,对我很有用。我记下了我应该审查的清单,我会按顺序仔细审查它们。再次非常感谢您。
    • 你是非常受欢迎的朋友,我很高兴能帮助你。快乐编码:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    • 2018-08-28
    相关资源
    最近更新 更多