Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

JPA - kaskady problem

39 views
Skip to first unread message

JK

unread,
Nov 27, 2007, 5:53:39 PM11/27/07
to
Witam, mam takie klasy

@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)

Newion

unread,
Nov 27, 2007, 7:12:42 PM11/27/07
to
JK napisał(a):

>
> 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)
>

"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.

Jacek Laskowski

unread,
Nov 29, 2007, 2:54:07 AM11/29/07
to
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).

Jacek

--
Jacek Laskowski
http://www.JacekLaskowski.pl

Brzezi

unread,
Nov 29, 2007, 3:51:58 AM11/29/07
to
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...


Pozdrawiam
Brzezi
--
[ E-mail: brz...@enter.net.pl ][ ]
[ Ekg: #3781111 ][ ]
[ LinuxUser: #249916 ][ ]

Daniel Janus

unread,
Nov 29, 2007, 3:57:52 AM11/29/07
to
Dnia 29.11.2007 Brzezi <usunto...@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, przesu...@nathell.korpus.pl
create_initial_thread(initial_function);
lose("CATS. CATS ARE NICE.\n");
-- Steel Bank Common Lisp, sbcl/runtime/runtime.c:425

JK

unread,
Nov 29, 2007, 12:54:28 PM11/29/07
to
Jacek Laskowski napisał(a):

> 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.

> Jacek

JK

Newion

unread,
Dec 1, 2007, 3:17:09 PM12/1/07
to
JK napisal:

>@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.

0 new messages