Не удается прочитать данные из сущности из-за исключения LazyInitializationException - PullRequest
0 голосов
/ 09 октября 2018

Я должен показать некоторые данные в интерфейсе, который объединен из двух объектов.Эти две сущности связаны следующим образом:

@Entity
@Table(name="T_LOAD_ORDERS")
@Data
public class LoadOrders {
    .
    .
    .
    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="SUPERVISOR")
    private MdUser supervisor;
    .
    .
    .
}

@Entity
@Table(name="T_MD_USER")
@Data
public class MdUser {

    @Id
    @Column(name="USER_ID")
    private String userId;
    .
    .
    .
    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private List<OrderStates> orderStates;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="SUPERVISOR")
    private List<LoadOrders> loadOrders;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private List<Staff> staffs;
}

Так что я должен получить данные из сущности LoadOrders и userId из MdUser.Я использую JPARepository из Spring, поэтому я вызываю findAll () для объекта LoadOrders.Пока это работает нормально.Но когда я добавляю эти несколько строк кода:

if (loadOrderEntity.getSupervisor() != null) {
    MdUser user = loadOrderEntity.getSupervisor();
    this.supervisor = user.getUserId();
} else {
    this.supervisor = null;
}

, я получаю это исключение:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.XXXX.XX.XXXX.data.entity.MdUser.orderStates, could not initialize proxy - no Session

Ну, я подумал, что я очень умно изменил бы названный тип fetch на eager, нокак показывает код, в этой сущности есть более ленивые извлечения.Изменение их всех на нетерпеливые звучит для меня довольно глупо и тоже не работает:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [de.fraport.bvd.mobisl.data.entity.MdUser.staffs, de.fraport.bvd.mobisl.data.entity.MdUser.orderStates]

Так что я могу сделать здесь?

РЕДАКТИРОВАТЬ

После намека Петра Подразы, что добавление @Transactional к методу, вызывающему данные, я изменил свой код, который читает из базы данных, следующим образом:

@Transactional(readOnly=true)
@GetMapping("/dispo/orderViewList")
private String showOrderList(@RequestParam("page") Optional<Integer> page, Model model) {
    page.ifPresent(p -> currentPage = p);

    Page<LoadOrders> pagedList = orderRepository.findAll(PageRequest.of(currentPage - 1, INITIAL_PAGE_SIZE));
    List<LoadOrder> orderList = service.createLoadOrderPage(pagedList); 

    model.addAttribute("page", orderList);
    model.addAttribute("currentPage", currentPage);
    model.addAttribute("totalPages", pagedList.getTotalPages());
    return "/dispo/orderViewList";
}

orderRepository расширяет JPARepository, а метод findAll () является реализацией, предоставляемой Spring.Но все равно это не работает.

@ EnableTransactionManagement предоставляется моим классом JPAConfig, который импортируется в основной класс приложения следующим образом:

@SpringBootApplication
@Import(value=JPAConfig.class)
public class WebApplication {

    @Autowired
    private JPAConfig config;

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Чтобы сделать аннотацию @Transactional, вы должны добавить аннотацию @EnableTransactionManagement в свой файл AppConfig.

Говоря о Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [de.fraport.bvd.mobisl.data.entity.MdUser.staffs, de.fraport.bvd.mobisl.data.entity.MdUser.orderStates]

Это происходит потому, что в терминах Hibernate вы на самом делеиспользуйте не List с, а Bag с, которые не являются упорядоченными коллекциями с возможными дубликатами.В классе MdUser у вас есть два свойства, которые связаны с одним и тем же свойством:

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
private List<OrderStates> orderStates;

и

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
private List<Staff> staffs; 

, поэтому в случае Eager выборка Hibernate не знаеткак развивать их обоих как басгов.Чтобы избежать этой проблемы, есть как минимум два способа заставить Hibernate разрешить эти свойства как реальные списки Hibernate:

  1. Добавить порядок для каждого объекта, т. Е. (При условии, что Staff имеет это свойство)

    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="USER_ID")
    @OrderBy("POSITION")
    private List<Staff> staffs;
    
  2. Заменить List на Set.Если вам не нужен какой-либо порядок, используйте Set вместо List, и это автоматически заставит Hibernate распознавать Коллекции как Наборы Hibernate.Это позволит избежать двусмысленности при извлечении

Надеюсь, это поможет

0 голосов
/ 09 октября 2018

У вас есть два варианта:

1) Не загружайте загруженные коллекции и исправляйте код, чтобы он выполнялся внутри сеанса.

2) Измените тип выборки, чтобы он загружался с нетерпением -этот подход потребует изменения типов сбора внутри класса MdUser с List на Set, поскольку вы не можете одновременно получать несколько пакетов.Подробнее о проблеме вы можете прочитать здесь: https://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html

...