Hibernate无法解决属性错误

时间:2014-06-21 17:12:23

标签: java hibernate lazy-loading

我目前无法解决Hibernate的问题,我收到了消息:

Your page request has caused a QueryException: could not resolve property: PERSON_ID of: library.model.Person [FROM library.model.Person p JOIN Book b ON p.PERSON_ID = b.PERSON_ID WHERE p.PERSON_ID = 2] error:

在以下方法中:

@Override
public Person getPersonAndBooks(Integer personId) {
    logger.info(PersonDAOImpl.class.getName() + ".listBooksForPerson() method called.");

    Session session = sessionFactory.openSession();                  
    Query query = session.createQuery("FROM Person p JOIN Book b ON p.PERSON_ID = b.PERSON_ID WHERE p.PERSON_ID = " + personId);                
    List<Person> persons = query.setResultTransformer(Transformers.aliasToBean(Person.class)).list();
    List<Book> books = persons.get(0).getBooks();
        for (Book b : books) {
           System.out.println("Here " + b.toString());
        }    
        return persons.get(0);  
    }        
    finally {
        session.close();
    }         
}

但我认为SQL中没有任何错误,它在Apache Derby中运行良好。

我已经在StackOverflow和其他地方尝试过很多东西,但没有解决问题。

简单应用程序中有两个类:

@Entity
@Table(name = "PERSON")
public class Person implements Serializable {

// Attributes.    
@Id
@Column(name="PERSON_ID", unique=true, nullable=false)    
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;

@Column(name="NAME", nullable=false, length=50)      
private String name;

@Column(name="ADDRESS", nullable=false, length=100)
private String address;

@Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;

@Column(name="EMAIL", nullable=false, length=50)
private String email;

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)     
private List<Book> books;

和书:

Entity
@Table(name = "BOOK")
public class Book implements Serializable {

// Attributes.
@Id
@Column(name="BOOK_ID", unique=true, nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer bookId;

@Column(name="AUTHOR", nullable=false, length=50)
private String author;

@Column(name="TITLE", nullable=false, length=50)
private String title;

@Column(name="DESCRIPTION", nullable=false, length=500)
private String description;

@Column(name="ONLOAN", nullable=false, length=5)
private String onLoan;

@ManyToOne
@JoinColumn(name="person_id")    
private Person person;

每个映射到数据库表:

CREATE TABLE PERSON (
  PERSON_ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),    
  NAME VARCHAR(50) NOT NULL,  
  ADDRESS VARCHAR(100) NOT NULL, 
  TELEPHONE VARCHAR(10) NOT NULL,
  EMAIL VARCHAR(50) NOT NULL,      
  CONSTRAINT PRIMARY_KEY_PERSON PRIMARY KEY(PERSON_ID)
)

书是:

CREATE TABLE BOOK (
  BOOK_ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),    
  AUTHOR VARCHAR(50) NOT NULL,  
  TITLE VARCHAR(100) NOT NULL, 
  DESCRIPTION VARCHAR(500) NOT NULL,
  ONLOAN VARCHAR(5) NOT NULL,
  PERSON_ID INTEGER,   
  CONSTRAINT PRIMARY_KEY_BOOK PRIMARY KEY(ID),
  CONSTRAINT FOREIGN_KEY_BOOK FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PERSON_ID)  
)

有人可以告诉我哪里出错了吗?

如果SQL最终有效,如果我使用正确的方法将输出转换为Person具有Book的arraylist的Person对象?

我为一个人获取书籍的方法是:

// Calls books.jsp for a Person.
@RequestMapping(value = "/books", method = RequestMethod.GET)
public String listBooks(@RequestParam("personId") String personId, 
                        Model model) {    
    logger.info(PersonController.class.getName() + ".listBooks() method called."); 


    Person person = personService.get(Integer.parseInt(personId));  
    List<Book> books = bookService.listBooksForPerson(Integer.parseInt(personId));                

    // Set view.
    model.addAttribute("person", person);
    model.addAttribute("books", books);
    return "view/books";
}

哪种方法有效。

完整堆栈跟踪如下:

  

你的页面请求导致了一个LazyInitializationException:懒得初始化一个角色集合:library.model.Person.books,无法初始化代理 - 没有会话错误:

org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294)
library.controller.PersonController.getLogin(PersonController.java:104)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:690)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:498)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:394)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:744)

4 个答案:

答案 0 :(得分:1)

您编写了HQL查询,就好像它是一个SQL查询一样。不是。 HQL和JPQL是不同的语言。

HQL从不使用表名和列名。它总是使用实体名称及其持久字段名称(即personId而不是PERSON_ID)及其关联。 HQL中的联接包括导航实体之间的关联。因此,HQL查询没有ON子句。

正确的HQL查询将是

 select p from Person p join p.books where p.id = :personId

请注意,我在查询中使用了一个必须绑定的命名参数,而不是使用连接,这是SQL注入攻击的开门(就像在SQL中一样)。

上述查询将选择由给定ID标识的人,除非它没有任何书籍。您不需要任何结果转换器来获取此查询的结果:它是Person实例。

我强烈建议你阅读the Hibernate documentation,它解释了HQL查询。

也就是说,您不需要任何查询来实现通过ID获取人员的方法。你所需要的只是

Person p = (Person) session.get(Person.class, personId);
// now you can display the person and its books.

答案 1 :(得分:0)

比HQL更安全的是使用criteria API

@RequestMapping(value = "/books", method = RequestMethod.GET)
public String listBooks(@RequestParam("personId") String personId, 
                        Model model) {    

    Criteria query = session.createCriteria(Person.class);
    query.addRestriction("personId", personId);
    Person me = query.list().get(1);
    List<Book> myBooks = me.getBooks();
    model.setAttribute("person", me);
    model.setAttribute("books", myBooks);
    return "view/books";
}

<强>更新

@Entity
@Table(name = "PERSON")
public class Person implements Serializable {

// Attributes.    
@Id
@Column(name="PERSON_ID", unique=true, nullable=false)    
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;

@Column(name="NAME", nullable=false, length=50)      
private String name;

@Column(name="ADDRESS", nullable=false, length=100)
private String address;

@Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;

@Column(name="EMAIL", nullable=false, length=50)
private String email;

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)     
private List<Book> books;
}

答案 2 :(得分:0)

如果我从控制器return (Person) session.get(Person.class, personId);获得人员后我理解正确这个人实例没有书籍,因为懒惰地加载书籍。当你调用person.getBooks()时,它需要一个开放的会话来加载书籍,但是在你的DAO会话中已经在finally块中关闭了内部导致LazyInitializationException: failed to lazily initialize a collection of role: library.model.Person.books, could not initialize proxy - no Session error:

尝试永久加载图书。

更改您的代码

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)     
private List<Book> books;

答案 3 :(得分:0)

在HQL中,不需要在连接中使用ON条件,hibernate将在运行时生成它。并且我们的HQL中只应使用我们的POJO变量名称。

FROM Person p JOIN p.book  b WHERE p.persionId = personid