Pobraniem kolekcji - Spring/Hibernate

0

Cześć.
Używam: SpringMVC, Hibernate, MySQL.

Mam problem z pobraniem kolekcji z bazy danych.
Pobieram użytkownika który relacją wiele do wielu jest połączony z Rolami (admin, user itd).

Kiedy pobieram użytkownika przez serwis, na stronie nie pojawia się żaden błąd. Dopiero w debugerze wyrzuca coś takiego:
user image

Przewertowałem stackoverflow i wydaje mi się że sesja zostaje zamknięta zanim jeszcze zostanie pobrana lista ról.
Problem w tym że zrobiłem chyba wszystko co wyczytałem i dalej jest to samo.

Wkleję po kolei najważniejsze fragmenty.

Model klasy:

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id_person;
(reszta pól)
    @ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinTable(name = "PERSON_ROLES", joinColumns = {@JoinColumn (name = "PERSON_ID")},inverseJoinColumns = {@JoinColumn(name="ROLE_ID")})
    private Set<Role> personRole = new HashSet<Role>();

DAO:

@Repository
public class PersonDAOImpl implements PersonDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
@SuppressWarnings("unchecked")
    public Person getPersonByEmail(String email) {
        List<Person> personList = new ArrayList<Person>();
Session session = this.sessionFactory.getCurrentSession();

personList = session.createQuery("from Person where email=?")
                .setParameter(0, email)
                .list();

        if (personList.size() > 0) {
            return personList.get(0);
        } else {
            return null;
        }

    }
}

Service:

@Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonDAO personDAO;

    public void setPersonDAO(PersonDAO personDAO) {
        this.personDAO = personDAO;
    }
    @Override
    @Transactional
    public Person getPersonByEmail(String email) {
        return this.personDAO.getPersonByEmail(email);
    }

Controller:

 @RequestMapping(value = "/registerSchool", method = RequestMethod.POST)
    private ModelAndView registerSchoolSave(@Valid @ModelAttribute("school") School school, BindingResult result,HttpServletRequest request){
        ModelAndView modelAndView = new ModelAndView();

        if(result.hasErrors()){
            modelAndView.setViewName("register/registerSchool");
            return  modelAndView;
        }
        Principal principal = request.getUserPrincipal();

        Person person = personService.getPersonByEmail(principal.getName());


        modelAndView.setViewName("register/registerSchoolSuccess");
        return modelAndView;
    }

front controller:

 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="personDAO" class="pl.lbednarski.edziennik.dao.PersonDAOImpl">
        <property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/>
    </bean>

    <bean id="personService" class="pl.lbednarski.edziennik.service.PersonServiceImpl">
        <property name="personDAO" ref="personDAO"/>
    </bean>

Połączenie z bazą jest ponieważ pobiera wszystkie pola oprócz kolekcji.

Ktoś ma pomysł albo widzi błąd?

Pozdrawiam
~eL

0

spróbuj zmodyfikować getPersonByEmail na:

public Person getPersonByEmail(String email) {
       Session session = sessionFactory.getCurrentSession();  //albo sessionFactory.openSession();
       Query query = session.createQuery("from Person where email=?").setParameter(0, email);
       List<Person> personList = query.list();
 
        if (personList != null) {
            return personList.get(0);
        }
        return null;
    }
1

Twój problem polega na tym, że próbujesz się dostać poza transakcją do danych których nie ma. Aby temu zaradzić masz kilka opcji.

  1. Zmienić na FetchType.EAGER przy kolekcji którą chcesz wyciągnać.
  2. Zrobić FETCH JOIN'a
  3. Wyciągnąć dane w transakcji, które będą Ci później potrzebne

Taka uwaga na boku, jeśli tylko pobierasz dane to oznacz metodę/serwis @Transactional(readOnly = ture). Wtedy dostawca może ale nie musi zoptymalizować pewne rzeczy(to jest tylko hint).

0

Zamiana Fetch na Eager pomogła ;) Dzięki!

1 użytkowników online, w tym zalogowanych: 0, gości: 1