这个问题几乎说明了一切。使用JPARepository我如何更新一个实体?
JPARepository只有一个save方法,它并没有告诉我它是创建还是更新。例如,我插入一个简单的对象到数据库User,它有三个字段:姓,名和年龄:
@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;
}
}
然后我简单地调用save(),这在这一点上实际上是插入到数据库:
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具有相同用户名和名字的用户实际上是EQUAL,并且现有实体应该被更新?重写等号并不能解决这个问题。
具体来说,我如何告诉spring-data-jpa拥有
相同的用户名和名字实际上是相等的,这是假定的
更新实体。重写等号不起作用。
为了这个特殊的目的,我们可以像这样引入一个复合键:
CREATE TABLE IF NOT EXISTS `test`.`user` (
`username` VARCHAR(45) NOT NULL,
`firstname` VARCHAR(45) NOT NULL,
`description` VARCHAR(45) NOT NULL,
PRIMARY KEY (`username`, `firstname`))
映射:
@Embeddable
public class UserKey implements Serializable {
protected String username;
protected String firstname;
public UserKey() {}
public UserKey(String username, String firstname) {
this.username = username;
this.firstname = firstname;
}
// equals, hashCode
}
下面是如何使用它:
@Entity
public class UserEntity implements Serializable {
@EmbeddedId
private UserKey primaryKey;
private String description;
//...
}
JpaRepository看起来是这样的:
public interface UserEntityRepository extends JpaRepository<UserEntity, UserKey>
然后,您可以使用下面的习惯用法:接受带有用户信息的DTO,提取姓名和名字并创建UserKey,然后使用这个组合键创建一个UserEntity,然后调用Spring Data save(),它应该为您整理所有内容。
如果你的主键是自动递增的,那么你必须设置主键的值。
对于save();方法作为update()工作。否则它将在db中创建一个新记录。
如果使用JSP表单,则使用隐藏字段设置主键。
Jsp:
<form:input type="hidden" path="id" value="${user.id}"/>
Java:
@PostMapping("/update")
public String updateUser(@ModelAttribute User user) {
repo.save(user);
return "redirect:userlist";
}
再看看这个:
@Override
@Transactional
public Customer save(Customer customer) {
// Is new?
if (customer.getId() == null) {
em.persist(customer);
return customer;
} else {
return em.merge(customer);
}
}
正如其他人回答的那样,save()方法是双重函数。它既可以保存也可以更新,如果你提供id它就会自动更新。
对于控制器类中的update方法,我建议使用@PatchMapping。下面是示例。
#保存方法POST
{
"username": "jhon.doe",
"displayName": "Jhon",
"password": "xxxyyyzzz",
"email": "jhon.doe@mail.com"
}
@PostMapping("/user")
public void setUser(@RequestBody User user) {
userService.save(user);
}
#更新方法
{
"id": 1, // this is important. Widly important
"username": "jhon.doe",
"displayName": "Jhon",
"password": "xxxyyyzzz",
"email": "jhon.doe@mail.com"
}
@PatchMapping("/user")
public void patchUser(@RequestBody User user) {
userService.save(user);
}
也许你想知道本我是从哪里来的。它来自数据库当然,你想要更新现有的数据,对吧?