2013-04-05 21 views
9

Jestem nowy w całej sprawie JPA, więc mam wiele pytań o najlepszy sposób obsługi JPA i utrzymywania.Najlepszy sposób obsługi scalania JPA?

  1. Mam obiekt użytkownika, który powinien zostać zaktualizowany (niektóre wartości, takie jak data i nazwa). Czy najpierw muszę scalić przekazany obiekt, czy bezpieczniej jest znaleźć nowy obiekt?

    Obecnie mój kod do aktualizacji użytkownika wygląda następująco:

    public void updateUserName(User user, String name) { 
        // maybe first merge it? 
        user.setName(name); 
        user.setChangeDate(new Date()); 
        em.merge(user); 
    } 
    

    Jak mogę mieć pewność, że użytkownik nie zostało zmanipulowane, zanim metoda aktualizacji nazywa? Czy bezpieczniej jest zrobić coś takiego:

    public void updateUserName(int userId, String name) { 
        User user = em.getReference(User.class, userId); 
        user.setName(name); 
        user.setChangeDate(new Date()); 
        em.merge(user); 
    } 
    

    Może inne rozwiązania? Oglądałem wiele filmów i widziałem wiele przykładów, ale wszystkie były inne i nikt nie wyjaśnił, jaka jest najlepsza praktyka.

  2. Jakie jest najlepsze podejście do dodawania dzieci do relacji? Na przykład mój obiekt użytkownika ma połączenie z wieloma grupami. Czy powinienem wywołać procedurę obsługi JPA dla użytkowników i po prostu dodać nową grupę do listy grup użytkowników, czy też powinienem utworzyć grupę w procedurze obsługi grup z persistem i dodać ją ręcznie do mojego obiektu użytkownika?

nadzieję, że ktoś tutaj ma pojęcia;)

+0

Zobacz http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge – GKislin

Odpowiedz

3

Pytanie 1

  • Sposób merge musi być wywoływana na jednorodzinnym podmiotu.
  • Metoda merge zwróci scalony obiekt dołączony do elementu entityManager.

Co to znaczy?

Obiekt jest odłączany, gdy obiekt entityManager, którego używasz do pobrania, zostanie zamknięty. (tj. przez większość czasu, ponieważ pobierasz go w poprzedniej transakcji).

W drugiej próbce kodu: użytkownik jest podłączony (ponieważ właśnie go pobierasz), więc wywoływanie połączenia jest bezużyteczne. (BTW: to nie jest getReference, ale find)

W twojej pierwszej próbce: nie znamy stanu użytkownika (odłączony podmiot czy nie?). Jeśli jest odłączony, warto zadzwonić pod numer merge, ale uważaj, aby merge nie zmodyfikować obiektu przekazanego jako argument. Więc tutaj jest moja wersja pierwszej próbki:

/** 
* @param user : a detached entity 
* @return : the attached updated entity 
**/ 
public User updateUserName(User user, String name) { 
    user.setName(name); 
    user.setChangeDate(new Date()); 
    return em.merge(user); 
} 

Pytanie 2

Może jakiś przykładowy kod, aby wyjaśnić, co rozumiesz przez JPA obsługi może pomóc nam zrozumieć swoje obawy. W każdym razie spróbuję ci pomóc.

Jeśli masz uporczywy użytkownika i trzeba utworzyć nową grupę i skojarzenie go z przetrwałym użytkownik:

User user = em.find(User.class, userId); 
Group group = new Group(); 
... 
em.persist(group); 
user.addToGroups(group); 
group.addToUsers(user); //JPA won't update the other side of the relationship 
         //so you have to do it by hand OR being aware of that 

Jeśli masz uporczywy użytkownika i trwałą grupę i trzeba je powiązać :

User user = em.find(User.class, userId); 
Group group = em.find(Group.class, groupId); 
... 
user.addToGroups(group); 
group.addToUsers(user); 

Uwagi ogólne

najlepszym Praktyki dotyczące tego wszystkiego naprawdę zależą od tego, czy zarządzasz transakcjami (a więc cyklem życia elementu entityager) w porównaniu z cyklem życia twoich obiektów.

Przez większość czasu: entityManager to obiekt żyjący naprawdę krótko. Z drugiej strony twoje obiekty biznesowe mogą żyć dłużej, więc będziesz musiał zadzwonić do scalania (i uważając na fakt, że scalanie nie zmienia obiektu przekazanego w argumencie !!!).

Użytkownik może zdecydować się na pobranie i modyfikację obiektów biznesowych w ramach tej samej transakcji (tj. Z tym samym obiektem entityManager): oznacza to o wiele więcej dostępu do bazy danych, a strategia ta musi być połączona z pamięcią podręczną drugiego poziomu ze względu na wydajność. Ale w tym przypadku nie będziesz musiał wywoływać scalania.

Mam nadzieję, że ta pomoc.

+0

Dziękuję za odpowiedź. Odnośnie do mojego pytania 1, czy nie jest to najprostszy sposób, aby ustawić moje pola, takie jak data i nowa nazwa w mojej metodzie, która wywołuje procedurę obsługi JPA i po prostu wywołać metodę "updateUser (User user)", aby po prostu scalić obiekt użytkownika i zapisać wszystkie zmiany zamiast tworzyć metody dla kilku przypadków użycia aktualizacji? – ManuPanu

6
  1. To zależy od tego, co chcesz osiągnąć i ile informacji masz na temat pochodzenia obiektu, który chcesz scalić.

    Po pierwsze, jeśli wywołasz em.merge(user) w pierwszym wierszu metody lub na końcu nie ma to znaczenia. Jeśli użyjesz JTA i CMT, twój obiekt zostanie zaktualizowany po zakończeniu wywołania metody. Jedyną różnicą jest to, że jeśli powołać em.merge(user) przed zmianą użytkownika należy użyć wracającą instancji zamiast swojego parametru, więc albo to jest:

    public void updateUserName(User user, String name) { 
        User managedUser = em.merge(user); 
        managedUser.setChangeDate(new Date()); 
        // no need of additional em.merge(-) here. 
        // JTA automatically commits the transaction for this business method. 
    } 
    

    lub

    public void updateUserName(User user, String name) { 
        user.setChangeDate(new Date()); 
        em.merge(user); 
        // JTA automatically commits the transaction for this business method. 
    } 
    

    Teraz o aktualizację podmiotu.
    Jeśli chcesz tylko zaktualizować niektóre dobrze zdefiniowane pola w twojej jednostce - użyj drugiego podejścia, ponieważ jest to bezpieczniejsze. Nie możesz być pewien, czy klient twojej metody nie zmodyfikował innych pól twojego obiektu. Dlatego też em.merge(-) zaktualizuje je również, co może nie być tym, co chcesz osiągnąć.

    Z drugiej strony - jeśli chcesz zaakceptować wszystkie zmiany wprowadzone przez użytkownika i po prostu zastąpić/dodać niektóre właściwości, takie jak changeDate w swoim przykładzie, pierwsze podejście jest również w porządku (scalanie całego obiektu przekazanego do metody biznesowej). tak naprawdę zależy od twojego przypadku użycia.

  2. Chyba zależy to od ustawień kaskadowych. Jeśli chcesz automatycznie utrwalać/scalać wszystkie Groups, gdy zmienia się obiekt User - można go po prostu dodać do kolekcji użytkownika (np. User#addGroup(Group g) { groups.add(g)}. Jeśli nie chcesz kaskadowania, zawsze możesz utworzyć własne metody, które będą propagować na drugą stronę relacji. Może to być coś takiego: User#addGroup(Group g), które automatycznie wywołuje g.addUser(this);.

Powiązane problemy