2012-08-09 4 views
83

Ну, вопрос в значительной степени говорит обо всем. Использование JPARepository как обновить объект?Как обновить объект, используя spring-data-jpa?

У JPARepository есть только метод сохранения, который не говорит мне, действительно ли это создание или обновление. Например, вставить простой объект в базе данных пользователя, который имеет три поля: Имя и фамилия и возраст:

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

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

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

Спасибо!

+1

Вы уверены, что ID перезаписывается при сохранении существующего объекта в базе данных ?? Никогда не было этого на моем проекте tbh –

+0

@ByronVoorbach, вы правы, просто проверили это. обновите вопрос также, thx – Eugene

+1

Привет, друг, вы можете посмотреть эту ссылку http://stackoverflow.com/questions/24420572/update-or-saveorupdate-in-crudrespository-is-there-any-options-available, вы можете быть подход вроде saveOrUpdate() – ibrahimKiraz

ответ

107

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

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

EDIT:

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

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

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

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

+0

ну да, я думаю, что знаю это. Я строго ссылался на spring-data-jpa. У меня есть две проблемы с этим ответом: 1) ценности бизнеса не должны быть частью первичного ключа - это известная вещь, верно? Поэтому наличие первого имени и последнего имени в качестве первичного ключа не является хорошим. И 2) Почему этот метод не называется create, а вместо этого сохраняет в spring-data-jpa? – Eugene

+0

@Eugene: Обновлено. – axtavt

+0

«save() в Spring Data JPA поддерживается слиянием() в простой JPA« вы действительно посмотрели на код? Я просто сделал это, и он оба подкреплялся либо упорством, либо слиянием. Он будет сохраняться или обновляться в зависимости от наличия идентификатора (первичного ключа). Это, я думаю, должно быть задокументировано в методе сохранения. Таким образом, сохранение фактически равномерное слияние или сохранение. – Eugene

52

Поскольку ответ на @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().

+0

эй его не работает! – bks4line

+2

Убедитесь, что вы запустили его в транзакции – hussachai

+1

Эй! Спасибо, я использую весны данных. Поэтому он автоматически позаботится о моем обновлении. S save (объект S); автоматически позаботится об обновлении. Мне не нужно было использовать ваш метод! В любом случае спасибо! – bks4line

4

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

1

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

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