2016-10-23 3 views
0

이 내 PersistenceUtil 클래스 ..병합은 어떻게 LazyInitException을 피할 수 있습니까?

package biz.tugay.learningjpa.persistence; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 

public class PersistenceUtilImpl implements PersistenceUtil { 

    private EntityManagerFactory entityManagerFactory; 

    public PersistenceUtilImpl(final String persistenceUnit) { 
     entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit); 
    } 

    public EntityManager getEntityManager() { 
     final EntityManager entityManager = entityManagerFactory.createEntityManager(); 
     return entityManager; 
    } 

    public void closeFactory() { 
     entityManagerFactory.close(); 
    } 
} 

그리고이 내 엔티티입니다 ..

Actor.java

package biz.tugay.learningjpa.model; 

import javax.persistence.*; 
import java.util.List; 

@Entity 
public class Actor { 

    private Integer id; 
    private String firstname; 
    private String lastname; 

    private List<Film> films; 

    @Id 
    @Column(name = "actor_id") 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer actor_id) { 
     this.id = actor_id; 
    } 

    @Basic 
    @Column(name = "first_name") 
    public String getFirstname() { 
     return firstname; 
    } 

    public void setFirstname(String first_name) { 
     this.firstname = first_name; 
    } 

    @Basic 
    @Column(name = "last_name") 
    public String getLastname() { 
     return lastname; 
    } 

    public void setLastname(String last_name) { 
     this.lastname = last_name; 
    } 

    @ManyToMany 
    @JoinTable(name = "film_actor", 
      joinColumns = @JoinColumn(name = "actor_id"), 
      inverseJoinColumns = @JoinColumn(name = "film_id") 
    ) 
    public List<Film> getFilms() { 
     return films; 
    } 

    public void setFilms(List<Film> films) { 
     this.films = films; 
    } 
} 

Film.java

package biz.tugay.learningjpa.model; 

import javax.persistence.*; 
import java.util.List; 

@Entity 
public class Film { 

    private Integer id; 
    private String title; 

    private List<Actor> actors; 

    @Id 
    @Column(name = "film_id") 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    @Basic 
    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    @ManyToMany 
    @JoinTable(name = "film_actor", 
      joinColumns = @JoinColumn(name = "film_id"), 
      inverseJoinColumns = @JoinColumn(name = "actor_id")) 
    public List<Actor> getActors() { 
     return actors; 
    } 

    public void setActors(List<Actor> actors) { 
     this.actors = actors; 
    } 
} 
입니다

그리고 나는 내 모델 2 개 서비스가 있습니다

ActorServiceImpl.java 아래와 같이 나는이 검사를

public final class ActorServiceImpl implements ActorService { 

    private final PersistenceUtil persistenceUtil; 

    public ActorServiceImpl(PersistenceUtil persistenceUtil) { 
     this.persistenceUtil = persistenceUtil; 
    } 

    @Override 
    public List<Actor> getActorsOfFilm(Film film) { 
     final EntityManager entityManager = persistenceUtil.getEntityManager(); 
     final Film mergedFilm = entityManager.merge(film); 
     final ArrayList<Actor> actors = new ArrayList<Actor>(); 
     actors.addAll(mergedFilm.getActors()); 
     entityManager.close(); 
     return actors; 
    } 
} 

FilmServiceImpl.java

public final class FilmServiceImpl implements FilmService { 

    private final PersistenceUtil persistenceUtil; 

    public FilmServiceImpl(final PersistenceUtil persistenceUtil) { 
     this.persistenceUtil = persistenceUtil; 
    } 

    @Override 
    public Film filmById(int filmId) { 
     final EntityManager entityManager = persistenceUtil.getEntityManager(); 
     final Film film = entityManager.find(Film.class, filmId); 
     entityManager.close(); 
     return film; 
    } 
} 

:

public class ActorServiceImplTest { 

    private PersistenceUtilImpl persistenceUtil; 
    private ActorServiceImpl actorService; 

    @Before 
    public void init() { 
     persistenceUtil = new PersistenceUtilImpl("sakiladb"); 
     actorService = new ActorServiceImpl(persistenceUtil); 
    } 

    @After 
    public void tearDown() { 
     persistenceUtil.closeFactory(); 
    } 

    @Test(expected = LazyInitializationException.class) 
    public void testGetActorsOfFilmLazyInit() { 
     final FilmServiceImpl filmService = new FilmServiceImpl(persistenceUtil); 
     final Film film = filmService.filmById(1); 
     for (Actor actor : film.getActors()) { 
      System.out.println(actor.getFirstname()); 
     } 
    } 

    @Test 
    public void testGetActorsOfFilm() { 
     final FilmServiceImpl filmService = new FilmServiceImpl(persistenceUtil); 
     final Film film = filmService.filmById(1); 
     final List<Actor> actorsOfFilm = actorService.getActorsOfFilm(film); 
     for (Actor actor : actorsOfFilm) { 
      System.out.println(actor.getFirstname()); 
     } 
    } 
} 

그래서 첫 번째 테스트에서는 LazyInitException이 발생합니다. EntityManager는 영화 배우를 얻는 시점까지 닫힙니다.

두 번째 테스트에 대해서는 "testGetActorsOfFilm"이라고합니다. 이 메시지는 데이터베이스에서 콘솔의 액터를 전달하고 인쇄합니다.이 작업은 entityManager.merge (film); 내가 이해하는 한. 우리는 분리 된 필름 객체를 전달하고 그것을 PersistenceContext에 병합 한 다음 구현에서 영화의 액터를 얻습니다.

는하지만, 무엇 내가 물어보고 싶은, 왜이 시험은 실패 않습니다

@Test 
public void testGetActorsOfFilm() { 
    final Film film = new Film(); 
    film.setId(1); 
    final List<Actor> actorsOfFilm = actorService.getActorsOfFilm(film); 
    for (Actor actor : actorsOfFilm) { 
     System.out.println(actor.getFirstname()); 
    } 
} 

나의 이해는, 나는 ID가 1 인 경우 필름 객체를 생성하고 서비스 방식으로 전달하고있다. 따라서 entityManager.merge (film)는 Database에서 필름을로드하고 Persistence Context와 동기화해야합니까? 그러나 내가보고하고 모든입니다

그래서 내가 혼란 스러워요
java.lang.NullPointerException 
    at java.util.ArrayList.addAll(ArrayList.java:559) 
    at biz.tugay.learningjpa.service.ActorServiceImpl.getActorsOfFilm(ActorServiceImpl.java:57) 

, 첫번째 상황에서 내가 가지고있는 분리 된 개체와 두 번째 상황의 차이는 무엇인가? 이드와 일만 병합하지 않습니까?

답변

1

merge(film) 데이터베이스에서 주어진 필름 ID와 필름을 얻을 수있는 모든 상태 film에서 managedFilm에, 사본 (의이 managedFilm를 부르 자) 및 managedFim를 반환합니다.

actors 목록은 기본적으로 null이며이 null 필드는 managedFilm으로 복사되므로 NullPointerException을 반복합니다.

당신은 당신의 의도가 관리 하나에 분리 된 필름의 상태를 복사 정말하지 않는 한, merge()를 사용하는 (따라서 잠재적으로 다음 정말 심하게 이름을 지정해야합니다 getActorsOfFilm()를 호출하여 필름을 수정하고 두 매우 필요는 없습니다 다른 책임).필름 대신 필름 ID를 전달하고 EntityManager.find()을 사용하여 데이터베이스에서 관리 필름을 가져옵니다.

+0

Null 포인터 예외를 피하는 적절한 방법은 getActorsOfFilm에서 EntityManager.find를 사용하는 것입니다. –

+0

예, 내 대답에 설명되어 있습니다. –

+0

어쨌든 actors.addAll (mergedFilm.getActors());를 피할 수 있습니까? 왜냐하면 내가 새로운 Collection에 필름을 추가하지 않는다면, 나는 여전히 LazyInitException을 얻을 것이다 .. –

관련 문제