Как обновить сущность с помощью spring-data-jpa?


ну вопрос в значительной степени говорит все. Использование JPARepository как обновить сущность?

JPARepository имеет только сохранить метод, который не говорит мне, если это создать или обновить на самом деле. Например, я вставляю простой объект в базу данных пользователя, который имеет три поля: firstname и lastname и 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;
  }
}

тогда я просто "сохраняю", что на данный момент является вставкой на самом деле:

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

ок все хорошо. Теперь я хочу чтобы обновить этого пользователя, скажем, изменить его возраст. Ну, я мог бы использовать запрос для этого либо QueryDSL, либо NamedQuery, что угодно. Но, учитывая, что я просто хочу использовать spring-data-jpa и JPARepository, как мне сказать, что вместо вставки я хочу сделать обновление?

в частности, как я могу сказать spring-data-jpa, что пользователи с одинаковым именем пользователя и именем пользователя фактически равны и что предполагается обновить сущность. Переопределение равных не сработало.

спасибо Ты!

5 108

5 ответов:

идентичность объектов определяется их первичными ключами. Так как firstname и lastname не являются частями первичного ключа, вы не можете сказать JPA лечить User s с тем же firstnames и lastnameы как равные, если они имеют разные userId s.

Итак, если вы хотите обновить User определить по его firstname и lastname, вам необходимо найти User С помощью запроса, а затем изменить соответствующие поля объекта, который вы нашли. Эти изменения будут сброшены в базу данных автоматически в конце транзакции, так что вам не нужно ничего делать, чтобы сохранить эти изменения явно.

EDIT:

возможно, я должен подробно остановиться на общей семантике JPA. Существует два основных подхода к проектированию API персистентности:

  • вставить / обновить подход. Когда вам нужно изменить базу данных, вы должны вызвать методы persistence API явно: вы вызываете insert вставить объект, или update для сохранения нового состояния объекта в базе данных.

  • единица подход к работе. В этом случае у вас есть набор объектов управлял библиотека настойчивость. Все изменения, которые вы вносите в эти объекты, будут автоматически сброшены в базу данных в конце единицы работы (т. е. в конце текущей транзакции в типичном случае). Когда вам нужно вставить новую запись в базу данных, вы делаете соответствующий объект управлял. управлял объекты идентифицируются по их первичным ключам, так что если вы создадите объект с предопределенным первичным ключом управлял, он будет связан с записью базы данных того же идентификатора, и состояние этого объекта будет автоматически распространяться на эту запись.

JPA следует более позднему подходу. save() весной данные JPA поддерживаются merge() в простом JPA, поэтому он делает вашу сущность управлял как описано выше. Это значит, что вызов save() на объекте с предопределенным идентификатором будет обновляться соответствующая запись базы данных, а не вставлять новую, а также объясняет, почему save() это не называется create().

так как ответ @axtavt фокусируется на JPA не spring-data-jpa

чтобы обновить объект путем запроса, сохранение не эффективно, потому что для этого требуется два запроса, и, возможно, запрос может быть довольно дорогим, поскольку он может присоединяться к другим таблицам и загружать любые коллекции, которые имеют fetchType=FetchType.EAGER

Spring-data-jpa поддерживает операции обновления.
Вы должны определить метод в интерфейсе репозитория.и аннотировал его с @Query и @Modifying.

@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);

@Query предназначен для определения пользовательского запроса и @Modifying это для того, чтобы сказать spring-data-jpa что этот запрос является операцией обновления, и оно требует executeUpdate() не executeQuery().

использование spring-data-JPA save(), У меня была та же проблема, что и @DtechNet. Я имею в виду, что каждый save() создавал новый объект вместо обновления. Чтобы решить эту проблему, мне пришлось добавить "версию", поданную в entity и связанную таблицу.

вот как я решил проблему:

User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);

вы можете просто использовать эту функцию с Save() JPAfunction, но объект отправлены в качестве параметра должно содержать существующий ID в базе данных, в противном случае он не будет работать, потому что Save() когда мы посылаем объекта без документов, он добавляет непосредственно строку в базе данных, но если мы посылаем объект с существующим кодом, он меняет столбцы в базе данных.

public void adduser(Userinfos u) {

User userFromDb = userRepository.findById(u.getid());

//crush the variables of the object found
userFromDb.setFirstname("john"); 
userFromDb.setLastname("dew");
userFromDb.setAge(16);

userRepository.save(userFromDb);
}