@Entity public class Company{ int id; String title; @OneToMany(mappedBy="company", fetch=FetchType.EAGER, cascade=CascadeType.ALL) Set<Employee> employees; [...]
}
@Entity public class Employee{ int id; String name; @ManyToOne Company company; [...]
}
i zdalnego session beana :
@Stateful public class CompanyManagerBean implements CompanyManagerRemote { public Company get(int id) {return em.find(Company.class,id);} public Company store(Company c) {return em.merge(c);}
}
I robię coś takiego w kliencie :
Company c = companyManager.get(4343); c.getEmployees().add(new Employee("Adam Kowalski")); companyManager.store(c);
Efekt jest taki że w bazie pojawia się nowy pracownik Adam Kowalski, ale jego pole company_id jest null. Przy ręcznym ustawianiu employee.setCompany(c) wszystko jest ok. Co zrobić z tym fantem?
Używawam JBossa 4.2.2GA z domyślnym dostawcą JPA (Hibarnate EM)
> Company c = companyManager.get(4343); > c.getEmployees().add(new Employee("Adam Kowalski")); > companyManager.store(c);
> Efekt jest taki że w bazie pojawia się nowy pracownik Adam > Kowalski, ale jego pole company_id jest null. Przy ręcznym > ustawianiu employee.setCompany(c) wszystko jest ok. Co zrobić z > tym fantem?
> Używawam JBossa 4.2.2GA z domyślnym dostawcą JPA (Hibarnate EM)
"Transparent POJO-oriented persistence implementations such as Hibernate do not implement managed associations. Contrary to CMR, Hibernate associations are all inherently unidirectional."
A to oznacza ze jezeli chcesz miec zwiazek dwukierunkowy, musisz okreslic zaleznosc dwukrotnie, dla kazdej encji oddzielnie. Zazwyczaj kod odpowiedzialny za wykonanie takiego powiazania umiejscawiany jest w jedej metodzie:
class Company { ... public void addEmployee(Employee empl) { getEmployees().add(empl); empl.setCompany(this);
} }
Pozdrawiam
-- Jesli jeszcze nie zwariowales, to znaczy ze jestes niedoinformowany.
JK wrote: > @Entity > public class Company{ > int id; > String title; > @OneToMany(mappedBy="company", fetch=FetchType.EAGER, > cascade=CascadeType.ALL) > Set<Employee> employees;
Odpowiedź dostałeś już od Newiona, więc ja pozwolę sobie zapytać o coś innego, ale wciąż związanego z Twoim przykładem.
1. Dlaczego użyłeś fetch=FetchType.EAGER? 2. Dlaczego użyłeś Set<Employee> zamiast List<Employee>?
Pytam, bo mam z czymś problem i sprowadziło się to do podobnych rozwiązań co u Ciebie i stąd mam pytanie, czy decyzje były świadome i również coś chciałeś zamodelować takimi konstrukcjami, czy po prostu tak wyszło ;-)
> @Entity > public class Employee{ > int id; > String name; > @ManyToOne > Company company;
I to mnie również zastanawia. Użyłeś @ManyToOne dla stworzenia dwukierunkowej asocjacji? Jeśli tak, to brakuje jeszcze elementu mappedBy. Dla pojedyńczej nie jest to wymagane (muszę to jeszcze sprawdzić, bo od wczoraj mam z tym mętlik).
Cz, 29 lis 2007 o 08:54 GMT, Jacek Laskowski napisał(a):
> 2. Dlaczego użyłeś Set<Employee> zamiast List<Employee>?
jezeli mapujesz kolekcje bez okreslonego porzadku, to po co List? Set jest prostym zbiorem bez porzadku...
sam w "normalnym" programowaniu raczej korzystam z List, ale jakos przy korzystaniu z hibernate/jpa zaczalem wykorzystywac Set do takich celow, wystarczy zajrzec tez do przykladow tych technologi, wszedzie jest Set jezeli kolekcje nie sa indeksowane...
Dnia 29.11.2007 Brzezi <usunto.brz...@enter.net.pl> napisał/a:
> Cz, 29 lis 2007 o 08:54 GMT, Jacek Laskowski napisał(a):
>> 2. Dlaczego użyłeś Set<Employee> zamiast List<Employee>?
> jezeli mapujesz kolekcje bez okreslonego porzadku, to po co List? Set jest > prostym zbiorem bez porzadku...
> sam w "normalnym" programowaniu raczej korzystam z List, ale jakos przy > korzystaniu z hibernate/jpa zaczalem wykorzystywac Set do takich celow, > wystarczy zajrzec tez do przykladow tych technologi, wszedzie jest Set > jezeli kolekcje nie sa indeksowane...
Mam wrażenie, że Hibernate się buntuje, kiedy klasa persystentna zawiera więcej niż jedną List i nie wyspecyfikuje się, na jakiej podstawie ma być ustalana kolejność na tych listach.
-- Daniel 'Nathell' Janus, GG #1631668, przesunma...@nathell.korpus.pl create_initial_thread(initial_function); lose("CATS. CATS ARE NICE.\n"); -- Steel Bank Common Lisp, sbcl/runtime/runtime.c:425
> Odpowiedź dostałeś już od Newiona, więc ja pozwolę sobie zapytać o coś > innego, ale wciąż związanego z Twoim przykładem.
> 1. Dlaczego użyłeś fetch=FetchType.EAGER?
Ponieważ przy pobieraniu entity beanów przez remote session beany entity jest od razu detached, więc kolekcje nie mogą być inicjalizowane później. Trzeba je albo ustawić albo jako EAGER, albo inicjalizować w Session Beanie (przez c.getEmployee().size() albo stosowania zapytania JPQL z joinami zamiast em.find(...)). Akurat w projekcie którym się teraz zajmuje wszystkie wyświetlane listy są pobierane zapytaniami które zwracają nia List<Company> ale List<Object[]> (różne pola beana Company), więc EAGER przy kolekcjach nie jest problemem.
> 2. Dlaczego użyłeś Set<Employee> zamiast List<Employee>?
Przy relacjach wiele do jednego może nie ma to takiego znaczenia, ale w relacjach wiele do wielu oszczędza to dużo pracu w pisaniu kodu testującego czy elementy się nie powtarzają.
> I to mnie również zastanawia. Użyłeś @ManyToOne dla stworzenia > dwukierunkowej asocjacji? Jeśli tak, to brakuje jeszcze elementu > mappedBy. Dla pojedyńczej nie jest to wymagane (muszę to jeszcze > sprawdzić, bo od wczoraj mam z tym mętlik).
Wydaje mi się że mappedBy powinny być tylko przy "właścicielu" czyli Company. Ale głowy nie dam.
>@Entity >public class Company{ >int id; >String title; >@OneToMany(mappedBy="company", fetch=FetchType.EAGER, >cascade=CascadeType.ALL) >Set<Employee> employees; >[...] >} >@Entity >public class Employee{ >int id; >String name; >@ManyToOne >Company company; >[...] >} > Wydaje mi sie ze mappedBy powinny byc tylko przy "wlascicielu" > czyli Company. Ale glowy nie dam.
> JK
Jest odwrotnie. mappedBy wskazuje nazwe atrybutu w encji bedacej wlascicielem relacji (czyli mappedBy jest przy encji nie bedacej wlascicielem relacji). Czyli w Twoim przykladzie wlascicielem relacji jest Employee.
Pozdrawiam -- Jesli jeszcze nie zwariowales, to znaczy ze jestes niedoinformowany.