Łukasz Kukawski

Łukasz Kukawski Deweloper aplikacji
internetowych

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Mam problem, mam pytanie

Mam trzy encje:
1)Artykuł
2)Sklep
3)Strona

Relację między encjami:

Jeden artykuł może mieć wiele sklepów, jeden sklep może mieć wiele artykułów.
Jeden artykuł może mieć jedną stronę.
Jeden sklep może mieć jedną stronę.

Jak to wygląda w kodzie:

Artykuł:

@OneToOne(fetch=FetchType.LAZY)
@Cascade({CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@JoinColumn(name = "strona_id")
private Strona strona;

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name="sklep_artykul",
joinColumns=@JoinColumn(name="artykul_id"),
inverseJoinColumns=@JoinColumn(name="sklep_id")
)
private Set<Sklep> sklepy = new HashSet<Sklep>();

Sklep:

@OneToOne( fetch=FetchType.LAZY)
@Cascade({CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@JoinColumn(name = "strona_id")
private Strona strona;

@ManyToMany(mappedBy="sklepy", fetch=FetchType.LAZY)
private Set<Artykul> artykuly = new HashSet<Artykul>();

Podczas dodawania artykułu udostępniam możliwość podpięcia kilku sklepów poprzez listę select multiple.


form:select path="sklepy" multiple
items="${sklepy}" itemLabel="nazwa" itemValue="id"

W kontrolerze który wywołuję widok z dodaniem artykułu dodaję initBInder aby odwzorować Stringa z formularza na listę sklepów:

@InitBinder
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) {
binder.registerCustomEditor(Set.class, "sklepy",
new CustomCollectionEditor(Set.class) {
@Override
protected Object convertElement(Object element) {
if (element != null) {
return sklepService.pobierzSklep(Integer
.parseInt(element.toString()));
}
return null;
}
});

Wszystko działa poprawnie po za jedną rzeczą.
Problem polega na tym że gdy generuję formularz z listą sklepów do wybrania, to hibernate generuję dodatkowe zbędne zapytania dla każdego sklepu, zaciągając powiązaną stronę.
W tej sytuacji potrzebuję tylko nazwę oraz id sklepu, nic więcej nie potrzebuję.
Gdy wygeneruję Select list pomijając atrybut path="sklepy" dodatkowe zapytania się nie generują.
Gdzie jest problem?Ten post został edytowany przez Autora dnia 10.03.14 o godzinie 15:43

konto usunięte

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Sam miałem taki problem i Hibernate ma problem z opcjonalną relacja OneToOne, FetchType.LAZY tu nigdy nie zadziała tak jakbyś chciał. Wyjście z tej sytuacji to sztuczne OneToOne na liście OneToMany

http://stackoverflow.com/questions/6290202/hibernate-o...
Adam Lesiak

Adam Lesiak Web developer - JEE
/ jQuery

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Powielone pytanie. Moja odpowiedź:

http://www.goldenline.pl/grupy/Komputery_Internet/spri...Ten post został edytowany przez Autora dnia 10.03.14 o godzinie 16:56
Łukasz Kukawski

Łukasz Kukawski Deweloper aplikacji
internetowych

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Dziękuję za odpowiedź, dodałem dwa tematy bo myślałem że do grupy Spring nikt nie zagląda, ostatni post był dość dawno.

Usunięcie fetch=FetchType.LAZY z OneToOne pomogło zniwelować ilość Selectów, dziękuję za wskazówkę.

Ale zastanawia mnie jedna rzecz, przy pobraniu wszystkich Sklepów i wypisaniu sysout-em Nazwy oraz Id w kontrolerze, nie powoduję wywołania dodatkowych Selectów.
A wygenerowanie listy w widoku w taki sposób:


form:select path="sklepy" multiple
items="${sklepy}" itemLabel="nazwa" itemValue="id"


generuję dodatkowe Select-y, dlaczego tak się dzieję, wiecie?
Adam Lesiak

Adam Lesiak Web developer - JEE
/ jQuery

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Hm. To coś na prawdę dziwnego. Selecty już powinien odpalić nawet bez pętli for i wyświetlania id/nazwy.

Wklej kod z kontrolera gdzie pobierasz listę 'sklepy'
Łukasz Kukawski

Łukasz Kukawski Deweloper aplikacji
internetowych

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Kontroler:



@RequestMapping(value = "/admin/artykuly", method = RequestMethod.GET)
public String pokazArtykuly(ModelMap model) {

Artykul artykul = new Artykul();

model.addAttribute("artykuly",
artykulService.pobierzWszystkieArtykuly());
model.addAttribute("artykul", artykul);
model.addAttribute("strona_id", 0);
model.addAttribute("kategorieSklepow",
kategoriaSklepyService.pobierzWszystkieDostepne());

//tutaj pobieram listę sklepów
model.addAttribute("sklepy",
sklepyService.pobierzWszystkieDostepne());


model.addAttribute("staraKategoria", 0);
model.addAttribute("textButton", "Zapisz");
model.addAttribute("actionZapiszArtykul", "/admin/artykuly/zapisz");
model.addAttribute("publikujOd", artykul.getStringPublikujOd())
.addAttribute("wyroznijArtykulDo", " ");

return "pokazArtykuly";
}


sklepyService:


@SuppressWarnings("unchecked")
@Override
public List<Sklep> pobierzWszystkieDostepne() {
Criteria crit = session.getCurrentSession().createCriteria(
Sklep.class);
crit.add(Restrictions.eq("status", true));
return crit.list();
}


Co jeszcze wkleić, jaką informację podać aby rozwikłać ten problem? Mam w ustawieniach dodane aby sesję hibernate można było używać w widoku:, czyli w web.xml:

<filter>
<display-name>OpenSessionInViewFilter</display-name>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Może tutaj leży problem?
Adam Lesiak

Adam Lesiak Web developer - JEE
/ jQuery

Temat: Hibernate, Java(Spring), ManyToMany i problem z...

Wydaje mi się, że różnica pomiędzy wyrzuceniem Id i Nazwa w pętli for w kontrolerze a pobraniem do items="${sklepy}" w form:select jest taka, ze w kontrolerze odwołujesz się tylko do Id i Nazwa a Spring form:select pobiera całe items, bo "nie wie" z czego tam będziesz chciał korzystać, mimo, że select wyświetla tylko Id i Nazwa. Możesz przecież odwołać się do Id, Nazwy i Strony w selekcie i tutaj twórcy Springa prawdopodobnie nie pozostawili wyboru dla serwera tylko załadowane jest wszystko, niezależnie od FetchType.

Skoro masz takie "sztywnie wiązane", że używasz CascadeType.DELETE_ORPHAN to możesz użyć z optional=false czyli: @OneToOne(fetch=FetchType.LAZY, optional=false) dla encji Strona. Jednak jeśli nie jest to problemem wydajnościowym, pozostawiłbym samo @OneToOne, bez niczego czyli domyślnie. Niech robi JOIN.

Następna dyskusja:

Spring + hibernate - proble...




Wyślij zaproszenie do