Cóż, pytanie w zasadzie mówi wszystko. Korzystanie z JPARepository jak zaktualizować encję?
JPARepository ma tylko metodę zapisywania , która nie mówi mi, czy faktycznie jest tworzona czy aktualizowana. Na przykład wstawić prosty obiekt do użytkownika bazy danych, który ma trzy pola: firstname
, lastname
i age
:
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
Następnie po prostu wywołuję save()
, która w tym momencie jest właściwie wstawką do bazy danych:
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
Na razie w porządku. Teraz chcę zaktualizować tego użytkownika, powiedzmy zmień jego wiek. W tym celu mógłbym użyć Query, QueryDSL lub NamedQuery, cokolwiek. Ale biorąc pod uwagę, że chcę po prostu użyć spring-data-jpa i JPARepository, jak mam to powiedzieć, że zamiast wstawki chcę wykonać aktualizację?
W szczególności, jak mam powiedzieć spring-data-jpa, że użytkownicy z tą samą nazwą użytkownika i imieniem są w rzeczywistości RÓWNI i że istniejący byt powinien zostać zaktualizowany? Zastąpienie równości nie rozwiązało tego problemu.
źródło
Odpowiedzi:
Tożsamość jednostek jest definiowana przez ich klucze podstawowe. Ponieważ
firstname
ilastname
nie są częściami klucza podstawowego, nie można nakazać JPA, aby traktowałyUser
te samefirstname
silastname
si równe, jeśli mają różneuserId
s.Tak więc, jeśli chcesz zaktualizować
User
zidentyfikowany przez niegofirstname
ilastname
, musisz znaleźć toUser
przez zapytanie, a następnie zmienić odpowiednie pola znalezionego obiektu. Zmiany te zostaną automatycznie wprowadzone do bazy danych pod koniec transakcji, dzięki czemu nie trzeba nic robić, aby jawnie zapisać te zmiany.EDYTOWAĆ:
Być może powinienem rozwinąć ogólną semantykę WZP. Istnieją dwa główne podejścia do projektowania interfejsów API trwałości:
podejście do wstawiania / aktualizacji . Gdy musisz zmodyfikować bazę danych, powinieneś jawnie wywołać metody API trwałości: wywołujesz,
insert
aby wstawić obiekt lubupdate
zapisać nowy stan obiektu w bazie danych.Podejście jednostki pracy . W tym przypadku masz zestaw obiektów zarządzanych przez bibliotekę trwałości. Wszystkie zmiany, które wprowadzisz w tych obiektach, zostaną automatycznie usunięte do bazy danych na końcu Jednostki Pracy (tj. Na koniec bieżącej transakcji w typowym przypadku). Kiedy trzeba wstawić nowy rekord do bazy danych, zarządza się odpowiednim obiektem . Zarządzane obiekty są identyfikowane przez ich klucze podstawowe, więc jeśli utworzysz obiekt z zarządzanym predefiniowanym kluczem podstawowym , zostanie on powiązany z rekordem bazy danych o tym samym identyfikatorze, a stan tego obiektu zostanie automatycznie propagowany do tego rekordu.
WZP stosuje to drugie podejście.
save()
w Spring Data JPA jest zabezpieczonymerge()
zwykłym JPA, dlatego zarządza twoją jednostką w sposób opisany powyżej. Oznacza to, że wywołaniesave()
obiektu o zdefiniowanym identyfikatorze spowoduje zaktualizowanie odpowiedniego rekordu bazy danych zamiast wstawienia nowego, a także wyjaśni, dlaczegosave()
nie jest wywoływanycreate()
.źródło
extends CrudRepository<MyEntity, Integer>
zamiast tego,extends CrudRepository<MyEntity, String>
jak powinien. To pomaga? Wiem, że to prawie rok później. Mam nadzieję, że pomoże to komuś innemu.Ponieważ odpowiedź @axtavt koncentruje się na
JPA
niespring-data-jpa
Aby zaktualizować jednostkę za pomocą zapytania, zapisywanie nie jest wydajne, ponieważ wymaga dwóch zapytań i być może zapytanie może być dość drogie, ponieważ może łączyć się z innymi tabelami i ładować dowolne kolekcje, które mają
fetchType=FetchType.EAGER
Spring-data-jpa
obsługuje operację aktualizacji.Musisz zdefiniować metodę w interfejsie repozytorium. I opatrzyć ją adnotacjami za pomocą
@Query
i@Modifying
.@Query
jest do zdefiniowania niestandardowego zapytania i@Modifying
jest za mówieniespring-data-jpa
, że ta kwerenda jest operacja aktualizacji i wymagaexecuteUpdate()
nieexecuteQuery()
.Możesz określić inne typy zwrotów:
int
- liczbę aktualizowanych rekordów.boolean
- prawda, jeśli aktualizowany jest rekord. W przeciwnym razie fałszywe.Uwaga : uruchom ten kod w transakcji .
źródło
To update an entity by querying then saving is not efficient
to nie jedyne dwie możliwości. Istnieje sposób na określenie id i uzyskanie obiektu wiersza bez zapytania go. Jeśli wykonasz a,row = repo.getOne(id)
a następnierow.attr = 42; repo.save(row);
obejrzysz dzienniki, zobaczysz tylko zapytanie o aktualizację.Możesz po prostu użyć tej funkcji z funkcją JPA save (), ale obiekt wysłany jako parametr musi zawierać istniejący identyfikator w bazie danych, inaczej nie zadziała, ponieważ save (), gdy wysyłamy obiekt bez identyfikatora, dodaje bezpośrednio wiersz w baza danych, ale jeśli wyślemy obiekt z istniejącym identyfikatorem, zmieni to kolumny już znalezione w bazie danych.
źródło
Jak już wspomnieli inni,
save()
sam zawiera operacje tworzenia i aktualizacji.Chcę tylko dodać suplement dotyczący tego, co kryje się za tą
save()
metodą.Po pierwsze, zobaczmy hierarchię rozszerzania / implementowania
CrudRepository<T,ID>
,Ok, niech sprawdzić
save()
wdrażania naSimpleJpaRepository<T, ID>
,Jak widać, sprawdzi najpierw, czy identyfikator istnieje, czy nie, jeśli jednostka już tam jest, tylko aktualizacja zostanie wykonana
merge(entity)
metodą, a jeśli nie, nowy rekord zostanie wstawionypersist(entity)
metodą.źródło
Korzystając z spring-data-jpa
save()
, miałem taki sam problem jak @DtechNet. Mam na myśli, że każdysave()
tworzył nowy obiekt zamiast aktualizacji. Aby rozwiązać ten problem, musiałem dodaćversion
pole do encji i powiązanej tabeli.źródło
Oto jak rozwiązałem problem:
źródło
@Transaction
powyższej metody dla kilku żądań db. W tym przypadku nie ma potrzebyuserRepository.save(inbound);
, zmiany są automatycznie usuwane.save()
metoda danych wiosennych pomoże Ci wykonać zarówno: dodanie nowego elementu, jak i aktualizację istniejącego elementu.Wystarczy zadzwonić
save()
i cieszyć się życiem :))źródło
Id
, zapisze go, jak mogę uniknąć zapisania nowego rekordu.źródło
W tym konkretnym celu można wprowadzić klucz złożony taki jak ten:
Mapowanie:
Oto jak z niego korzystać:
JpaRepository wyglądałby tak:
Następnie możesz użyć następującego idiomu: zaakceptuj DTO z informacjami o użytkowniku, wyodrębnij nazwę i imię i utwórz UserKey, następnie utwórz UserEntity za pomocą tego klucza złożonego, a następnie wywołaj Spring Data save (), który powinien wszystko dla ciebie rozwiązać.
źródło