Eug*_*ene 171 java jpa spring-data-jpa
好吧,这个问题几乎说明了一切.使用JPARepository如何更新实体?
JPARepository只有一个save方法,它不会告诉我它是否实际创建或更新.例如,我将一个简单的Object插入数据库User,它有三个字段: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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我只是"保存",此时实际上是一个插入:
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);
Run Code Online (Sandbox Code Playgroud)
好的一切都很好.现在我想更新这个用户,比如改变他的年龄.好吧,无论是QueryDSL还是NamedQuery,我都可以使用Query.但是,考虑到我只想使用spring-data-jpa和JPARepository,我怎么告诉它而不是插入我想要更新?
具体来说,我如何告诉spring-data-jpa具有相同用户名和名字的用户实际上是EQUAL并且它应该更新实体.压倒平等不起作用.
谢谢!
axt*_*avt 184
实体的身份由其主键定义.由于firstname并且lastname不是主键的一部分,如果它们具有不同的s ,则不能告诉JPA User使用相同的firstnames和lastnames 来对待userIds.
所以,如果你想更新User确定了其firstname和lastname,你需要找到User一个查询,然后更改对象的相应字段中输入您发现的.这些更改将在事务结束时自动刷新到数据库,因此您无需执行任何操作即可明确保存这些更改.
编辑:
也许我应该详细说明JPA的整体语义.设计持久性API有两种主要方法:
插入/更新方法.当您需要修改数据库时,应该显式调用持久性API的方法:调用insert插入对象,或者将对象的update新状态保存到数据库.
工作单元方法.在这种情况下,您有一组由持久性库管理的对象.您对这些对象所做的所有更改将在工作单元结束时自动刷新到数据库(即在典型情况下在当前事务结束时).当您需要将新记录插入数据库时,您可以管理相应的对象.托管对象由其主键标识,因此,如果您使用预定义的主键托管对象,则它将与具有相同ID的数据库记录关联,并且此对象的状态将自动传播到该记录.
JPA遵循后一种方法.save()在Spring Data中,JPA merge()以普通JPA为后盾,因此它可以使您的实体按上述方式进行管理.这意味着调用save()具有预定义id的对象将更新相应的数据库记录而不是插入新记录,并且还解释了为什么save()不被调用create().
hus*_*hai 117
由于@axtavt的回答JPA不关注spring-data-jpa
要通过查询来更新实体,那么保存效率不高,因为它需要两个查询,并且可能查询可能非常昂贵,因为它可能会加入其他表并加载任何有 fetchType=FetchType.EAGER
Spring-data-jpa支持更新操作.
您必须在Repository接口中定义方法.并使用@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);
Run Code Online (Sandbox Code Playgroud)
@Query是用于定义自定义查询,并@Modifying可以告诉spring-data-jpa这个查询是更新操作,它需要executeUpdate()不executeQuery().
Kal*_*ium 18
您可以简单地将此函数与save()JPAfunction一起使用,但是作为参数发送的对象必须在数据库中包含一个现有的id,否则它将不起作用,因为当我们发送不带id的对象时,save()会直接在其中添加一行数据库,但是如果我们发送一个具有现有ID的对象,它将更改数据库中已找到的列。
public void updateUser(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);
}
Run Code Online (Sandbox Code Playgroud)
Eug*_*ene 15
正如其他人已经提到的那样,它save()本身包含创建和更新操作.
我只想添加关于该save()方法背后的补充.
首先,让我们看看扩展/实现层次结构CrudRepository<T,ID>,

好的,让我们检查一下save()实施情况SimpleJpaRepository<T, ID>,
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,它将首先检查ID是否存在,如果实体已经存在,则仅通过merge(entity)方法进行更新,否则,通过persist(entity)方法插入新记录.
使用 java 8,您可以在 UserService 中使用存储库的 findById
@Service
public class UserServiceImpl {
private final UserRepository repository;
public UserServiceImpl(UserRepository repository) {
this.repository = repository;
}
@Transactional
public void update(User user) {
repository
.findById(user.getId()) // returns Optional<User>
.ifPresent(user1 -> {
user1.setFirstname(user.getFirstname);
user1.setLastname(user.getLastname);
repository.save(user1);
});
}
}
Run Code Online (Sandbox Code Playgroud)
使用spring-data-jpa save(),我遇到了与@DtechNet相同的问题.我的意思是每个save()都在创建新对象而不是更新.为了解决这个问题,我不得不在实体和相关表中添加"版本".
小智 6
spring datasave()方法将帮助您执行两项操作:添加新项目和更新现有项目。
只需致电save()并享受生活:))
这就是我解决问题的方法:
User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
307268 次 |
| 最近记录: |