这个问题几乎说明了一切。使用JPARepository,我如何更新一个实体?
JPARepository只有一个save方法,它并不告诉我它实际上是create还是update。例如,我向数据库用户插入一个简单的对象,它有三个字段: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;
}
}
然后我只需调用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数据jpa和JPARepository,我如何告诉它我想要的是更新而不是插入呢?
具体地说,我如何告诉spring-data-jpa具有相同用户名和firstname的用户实际上是相等的,并且应该更新现有的实体?重写equals并不能解决这个问题。
因为@axtavt的答案关注的是jpa
而不是spring-data-jpa
若要通过查询更新实体,则保存并不高效,因为它需要两个查询,而且查询可能会非常昂贵,因为它可能会连接其他表并加载任何具有FetchType=FetchType.Eage
的集合
spring-data-jpa
支持更新操作。
必须在存储库接口中定义方法。并用@query
和@modify
对其进行注释。
@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
用于定义自定义查询,@modify
用于告诉spring-data-jpa
该查询是更新操作,它需要executeUpdate()
而不是executeQuery()
。
您可以指定其他返回类型:int
-正在更新的记录数。boolean
-如果有正在更新的记录,则为true。否则为false。
注意:在事务中运行此代码。
实体的标识由其主键定义。由于firstname
和lastname
不是主键的一部分,如果userid
不同,则不能告诉JPA将具有相同firstname
和lastname
的user
视为相等。
因此,如果要更新由firstname
和lastname
标识的用户
,则需要通过查询找到该用户
,然后更改找到的对象的相应字段。这些更改将在事务结束时自动刷新到数据库中,这样您就不需要做任何事情来显式保存这些更改。
编辑:
也许我应该详细介绍一下JPA的整体语义。持久性API的设计有两种主要方法:
>
插入/更新方法。当需要修改数据库时,应显式调用持久性API的方法:调用insert
插入对象,或调用update
将对象的新状态保存到数据库。
工作单元法。在本例中,您有一组由持久性库管理的对象。您对这些对象所做的所有更改都将在工作单元结束时(典型情况下是在当前事务结束时)自动刷新到数据库中。当需要向数据库中插入新记录时,将相应的对象托管。托管对象由其主键标识,因此,如果您将具有预定义主键的对象设置为托管对象,则该对象将与具有相同id的数据库记录相关联,并且该对象的状态将自动传播到该记录。
JPA采用后一种方法。Spring Data JPA中的save()
由纯JPA中的merge()
支持,因此它使您的实体按照上面所述进行管理。这意味着对具有预定义id的对象调用save()
将更新相应的数据库记录,而不是插入新的记录,并且还解释了为什么save()
不被称为create()
。
问题内容: 这个问题几乎说明了一切。使用JPARepository如何更新实体? JPARepository只有一个 save 方法,它不会告诉我它是否实际上是在创建或更新。例如,我插入一个简单的对象数据库的用户,其中有三个领域:,和: 然后,我简单地调用,这实际上是数据库的插入: 到目前为止,一切都很好。现在,我想更新此用户,例如更改其年龄。为此,我可以使用QueryDSL或NamedQuery
我正在尝试使用Querydsl(4.1.4)查询JPA,如本文http://www.Querydsl.com/static/Querydsl/latest/reference/html/ch02.html#jpa_integration所述。我使用Hibernate(5.2.12.final)作为JPA后端。我使用和处理器从JPA注释类生成Querydsl查询类型。 这将打印: 原始JpaUpda
我正在尝试更新我的用户实体,我想到了一个错误:错误:NULL值违反了“id”列的Not NULL约束详细信息:失败的行包含(null,1,1) 这个问题肯定源于我在用户和配置文件之间的关系,即n-n
我有一些实体类,其id配置如下 接下来是我的问题。例如,第一天,我获取所有记录并保存它们。但是第二天我会再次得到所有的记录,包括第一天已经保存的记录。当我试着拯救第二天的时候会发生什么?是所有记录都将再次插入还是Spring数据只插入新记录,从第一天开始的旧记录将被更新?我需要第二种情况下的行为
因此,我看了关于使用Spring数据的JPA的各种教程,在许多情况下都有不同的做法,我不太确定正确的方法是什么。 假设存在follwing实体: 我们还有一个DTO,它在服务层中检索,然后交给控制器/客户端。 因此,现在假设客户想要在webui中更改他的名称--然后将会有一些控制器操作,其中将会有更新的DTO(使用旧ID和新名称)。 现在我必须将这个更新的DTO保存到数据库中。 不幸的是,目前没有