I've stumbled upon the LazyInitializationException while trying to learn JavaEE.
There's tons of topics on SO for dealing with the famous exception, but most of them involve Spring or a Hibernate-specific approach - what I'm looking for is how to deal with it using JPA (Hibernate as a provider) and JavaEE.
Using hibernate.enable_lazy_load_no_trans works, but everywhere I look people say to use it with caution.
The Open Session In View pattern is another solution that is considered as bad practice.
I found an article:
http://ift.tt/1LM8we7
The Fetch Query solution looks good (and safe!), but the amount of queries that have to be written (especially after a application grows) is terrifying...
It just feels there must be better way of lazy loading.
I'll just provide a sample app in which I'm dealing with the exception, perhaps it may be helpful...
Entities:
@Entity
@Table(name = "author")
@NamedQueries({
@NamedQuery(name = Author.findAll, query = "SELECT a FROM Author a"),
@NamedQuery(name = Author.findById, query = "SELECT a FROM Author a WHERE a.id = :id"),
@NamedQuery(name = Author.findByName, query = "SELECT a FROM Author a WHERE a.name = :name"),
@NamedQuery(name = Author.findBySurname, query = "SELECT a FROM Author a WHERE a.surname = :surname"),
@NamedQuery(name = Author.findByNameAndSurname, query = "SELECT a FROM Author a WHERE a.name = :name AND a.surname = :surname"),
@NamedQuery(name = Author.findByBirthdate, query = "SELECT a FROM Author a WHERE a.birthdate = :birthdate")
})
public class Author {
public static final String findAll = "Author.findAll";
public static final String findById = "Author.findById";
public static final String findByName = "Author.findByName";
public static final String findBySurname = "Author.findBySurname";
public static final String findByNameAndSurname = "Author.findByNameAndSurname";
public static final String findByBirthdate = "Author.findByBirthdate";
@Id
@Column(name = "id", nullable = false, insertable = true, updatable = true)
@SequenceGenerator(name = "author_id_seq", sequenceName = "author_id_seq", allocationSize = 1)
@GeneratedValue(generator = "author_id_seq", strategy = GenerationType.SEQUENCE)
private long id;
@Basic
@Column(name = "name", nullable = false, insertable = true, updatable = true, length = 50)
private String name;
@Basic
@Column(name = "surname", nullable = false, insertable = true, updatable = true, length = 100)
private String surname;
@Basic
@Column(name = "birthdate", nullable = true, insertable = true, updatable = true)
private Timestamp birthdate;
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Book> bookList;
gettters and setters...
@Entity
@Table(name = "book")
@NamedQueries({
@NamedQuery(name = Book.findAll, query = "SELECT b FROM Book b"),
@NamedQuery(name = Book.findById, query = "SELECT b FROM Book b WHERE b.id = :id"),
@NamedQuery(name = Book.findByName, query = "SELECT b FROM Book b WHERE b.name = :name"),
@NamedQuery(name = Book.findByAuthor, query = "SELECT b FROM Book b WHERE b.author = :author"),
@NamedQuery(name = Book.findByPublisher, query = "SELECT b FROM Book b WHERE b.publisher = :publisher")
})
public class Book {
public static final String findAll = "Book.findAll";
public static final String findById = "Book.findById";
public static final String findByName = "Book.findByName";
public static final String findByAuthor = "Book.findByAuthor";
public static final String findByPublisher = "Book.findByPublisher";
@Id
@Column(name = "id", nullable = false, insertable = true, updatable = true)
@SequenceGenerator(name = "book_id_seq", sequenceName = "book_id_seq", allocationSize = 1)
@GeneratedValue(generator = "book_id_seq", strategy = GenerationType.SEQUENCE)
private long id;
@Basic
@Column(name = "name", nullable = false, insertable = true, updatable = true, length = 200)
private String name;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "author_id", referencedColumnName = "id")
private Author author;
getters and setters...
Sample DAO:
public class DAO<T> {
@Inject
@Bookstore
protected EntityManager em;
public void persist(T object) {
em.getTransaction().begin();
em.persist(object);
em.getTransaction().commit();
}
public void merge(T object) {
em.getTransaction().begin();
em.merge(object);
em.getTransaction().commit();
}
public void remove(T object) {
em.getTransaction().begin();
em.remove(object);
em.getTransaction().commit();
}
}
public class AuthorDAO extends DAO<Author> {
public Author findById(long id) {
return (Author) em.createNamedQuery(Author.findById).setParameter("id", id).getSingleResult();
}
public List<Author> findAll() {
return em.createNamedQuery(Author.findAll).getResultList();
}
public List<Author> findByName(String name) {
return em.createNamedQuery(Author.findByName).setParameter("name", name).getResultList();
}
public List<Author> findBySurname(String surname) {
return em.createNamedQuery(Author.findBySurname).setParameter("surname", surname).getResultList();
}
public List<Author> findByNameAndSurname(String name, String surname) {
return em.createNamedQuery(Author.findByNameAndSurname).setParameter("name", name).setParameter("surname", surname).getResultList();
}
public List<Author> findByBirthdate(Timestamp birthdate) {
return em.createNamedQuery(Author.findByBirthdate).setParameter("birthdate", birthdate).getResultList();
}
}
A CDI bean from which I'm trying to retrieve the authors book list to show in a JSF page:
@Named("book")
@RequestScoped
public class BookBB {
@Inject
@FromContext
private Author author;
public List<Book> getBookList() {
return author.getBookList();
}
}
Simplest ever EntityManager producer:
public class EntityManagerProducer {
@PersistenceContext(unitName = "simple-bookstore")
private EntityManager entityManager;
@Produces
@Bookstore
public EntityManager getEntityManager() {
return entityManager;
}
public void disposeEntityManager(@Disposes @Bookstore EntityManager entityManager) {
entityManager.close();
}
}
Last, but not least - the persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://ift.tt/1cKbVbQ" version="2.1">
<persistence-unit name="simple-bookstore">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/PostgresqlDS</jta-data-source>
<class>db.entity.Author</class>
<class>db.entity.Book</class>
<class>db.entity.Publisher</class>
<class>db.entity.SchemaVersion</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/bookstore"/>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
<property name="hibernate.connection.username" value="bookstore"/>
<property name="hibernate.connection.password" value="bookstore"/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Aucun commentaire:
Enregistrer un commentaire