2016-10-23 5 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; 
    } 
} 

у меня есть 2 теста, как показано ниже:

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 (фильм); насколько я понимаю. Мы передаем отдельный объект фильма, мы объединим его в 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()); 
    } 
} 

Мое понимание, я создаю объект Film, где идентификатор 1 и передать его в метод обслуживания. Итак, entityManager.merge (фильм) должен загрузить фильм из базы данных и синхронизировать его с контекстом сохранения? Однако все, что я вижу это:

java.lang.NullPointerException 
    at java.util.ArrayList.addAll(ArrayList.java:559) 
    at biz.tugay.learningjpa.service.ActorServiceImpl.getActorsOfFilm(ActorServiceImpl.java:57) 

Так что я смущен, в чем разница между обособленным субъектом я в первом случае и во втором положении? Не сливается ли только с id?

ответ

1

merge(film) получает пленку с данной пленкой ID из базы данных (назовем его managedFilm), копирует все государства от film до managedFilm и возвращает managedFim.

Поскольку список actors по умолчанию является нулевым, а так как это пустое поле копируется в managedFilm, итерация на нем вызывает исключение NullPointerException.

Вы не должны использовать merge(), если только вы не намерены копировать состояние снятой пленки на управляемый (и, таким образом, потенциально модифицировать фильм, позвонив по номеру getActorsOfFilm(), который тогда был бы очень плохо назван и имел бы два очень разные обязанности).Просто передайте идентификатор фильма, а не фильм, и получите управляемый фильм из базы данных, используя EntityManager.find().

+0

Итак, правильный способ избежать Null Pointer Exception - использовать EntityManager.find в getActorsOfFilm? –

+0

Да, как объясняет мой ответ. –

+0

Есть ли все равно, чтобы избежать acts.addAll (mergedFilm.getActors()) ;? Потому что, если я не добавлю фильмы к новой коллекции, я все равно получу LazyInitException .. –

 Смежные вопросы

  • Нет связанных вопросов^_^