保存后刷新并获取一个实体(JPA / Spring Data / Hibernate) [英] Refresh and fetch an entity after save (JPA/Spring Data/Hibernate)
问题描述
我有两个简单的实体 Something
和 Property
。
Something
实体与 Property
有多对一的关系,所以当我创建一个新的 Something
行,我分配一个现有的 Property
。
东西:
@Entity
@Table(name =something)
public class Something implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private长ID;
@Column(name =name)
私有字符串名称;
@Column(name =owner)
private String owner;
@ManyToOne
私有财产;
// getters and setters
@Override
public String toString(){
returnSomething {+
id = + getId()+
,name ='+ getName()+'+
,owner ='+ getOwner()+'+
, property =+ getProperty()+
};
属性:
@Entity
@Table(name =property)
public class Property实现Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private长ID;
@Column(name =shape)
私人字符串形状;
@Column(name =color)
private String color;
@Column(name =dimension)
private Integer dimension;
// getters and setters
@Override
public String toString(){
returnProperty {+
id = + getId()+
,shape ='+ getShape()+'+
,color ='+ getColor()+'+
, dimension ='+ getDimension()+'+
};
$ / code $ / pre
这是 SomethingRepository
(Spring):
$ b $ pre $ @SuppressWarnings(unused)
@Repository
public interface SomethingRepository扩展JpaRepository< Something,Long> {
}
通过REST控制器和JSON,我想创建一个新的 Something
:
@RestController
@RequestMapping (/ api)
公共类SomethingResource {
private final SomethingRepository somethingRepository;
SomethingResource(SomethingRepository somethingRepository){
this.somethingRepository = somethingRepository;
$ b @PostMapping(/ somethings)
public Something createSomething(@RequestBody Something something)throws URISyntaxException {
Something result = somethingRepository.save(something) ;
返回结果;
$ b这是输入中的JSON(<$ c
$ b $ $ $ $
name:MyName,
owner:MySelf,
property:{
id :1
}
}
<问题是:在方法 .save(something)
之后,变量 result
包含持久化实体,但没有字段属性
,验证过(它们是 null
):
输出JSON:
{
id:1,
name :MyName,
owner:MySelf,
property:{
id:1,
shape:null,
color:null,
dimension:null
}
}
我希望它们在保存操作后被验证/返回。
为了解决这个问题,我必须注入/声明 Enti tyManager
在REST控制器中,并调用方法 EntityManager.refresh(something)
(或者我必须调用)。 findOne(something.getId())
方法拥有完整的持久化实体):
@RestController
@RequestMapping(/ api)
@Transactional
public class SomethingResource {
private final SomethingRepository somethingRepository;
private final EntityManager em;
public SomethingResource(SomethingRepository somethingRepository,EntityManager em){
this.somethingRepository = somethingRepository;
this.em = em;
$ b @PostMapping(/ somethings)
public Something createSomething(@RequestBody Something something)throws URISyntaxException {
Something result = somethingRepository.save(something) ;
em.refresh(result);
返回结果;
$ / code $ / pre
有了这个解决方法,我有了预期的保存头(使用正确的JSON):
{
id:4,
name: MyName,
owner:MySelf,
property:{
id:1,
shape:Rectangle,
color:Red,
dimension:50
}
}
是否有自动方法/注释,使用JPA或Spring或Hibernate,以便拥有完整持久实体?
我会喜欢避免在每个REST或Service类中声明EntityManager,或者我希望避免在每次需要新刷新的持久实体时调用.findOne(Long)方法。
非常感谢,
Andrea
解决方案这还不够:
Something result = somethingRepository.save(something);
您需要手动合并传入实体:
Something dbSomething = somethingRepository.findOne(
Something.class,something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
somethingRepository.save(dbSomething);
由于属性
属性使用默认值 FetchType.EAGER
,实体应该已经初始化属性
属性。
但是,调用Repository两次来自REST控制器。你应该有一个服务层来完成 @Transactional
服务方法中的所有功能。这样,你不需要重新保存实体,因为它已经被管理。
@Transactional
public Something mergeSomething (Something something){
Something dbSomething = somethingRepository.findOne(
Something.class,something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
return dbSomething;
}
现在,您需要谨慎合并您发送的每个属性。在你的情况下,如果你为属性
发送 null
,你应该决定是否应该取消不管是否参考@ManyToOne
。因此,这取决于您当前的应用程序业务逻辑要求。
更新
如果您确定始终发送返回先前提取的实体,您可以使用 merge
。
em.refresh(结果);
但是您的属性
属性只是一个id ,而不是实际的子实体,所以你必须在服务层自己解决。
I've these two simple entities Something
and Property
.
The Something
entity has a many-to-one relationship to Property
, so when I create a new Something
row, I assign an existing Property
.
Something:
@Entity
@Table(name = "something")
public class Something implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "owner")
private String owner;
@ManyToOne
private Property property;
// getters and setters
@Override
public String toString() {
return "Something{" +
"id=" + getId() +
", name='" + getName() + "'" +
", owner='" + getOwner() + "'" +
", property=" + getProperty() +
"}";
}
Property:
@Entity
@Table(name = "property")
public class Property implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "shape")
private String shape;
@Column(name = "color")
private String color;
@Column(name = "dimension")
private Integer dimension;
// getters and setters
@Override
public String toString() {
return "Property{" +
"id=" + getId() +
", shape='" + getShape() + "'" +
", color='" + getColor() + "'" +
", dimension='" + getDimension() + "'" +
"}";
}
}
This is the SomethingRepository
(Spring):
@SuppressWarnings("unused")
@Repository
public interface SomethingRepository extends JpaRepository<Something,Long> {
}
Through a REST controller and a JSON, I want to create a new Something
:
@RestController
@RequestMapping("/api")
public class SomethingResource {
private final SomethingRepository somethingRepository;
public SomethingResource(SomethingRepository somethingRepository) {
this.somethingRepository = somethingRepository;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
return result;
}
}
This is the JSON in input (the property
id
1 is an existing row in the database):
{
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1
}
}
The problem is: after the method .save(something)
, the variable result
contains the persisted entity, but without the fields of field property
, validated (they are null
):
Output JSON:
{
"id": 1,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": null,
"color": null,
"dimension": null
}
}
I expect that they are validated/returned after the save operation.
To workaround this, I have to inject/declare the EntityManager
in the REST controller, and call the method EntityManager.refresh(something)
(or I have to call a .findOne(something.getId())
method to have the complete persisted entity):
@RestController
@RequestMapping("/api")
@Transactional
public class SomethingResource {
private final SomethingRepository somethingRepository;
private final EntityManager em;
public SomethingResource(SomethingRepository somethingRepository, EntityManager em) {
this.somethingRepository = somethingRepository;
this.em = em;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
em.refresh(result);
return result;
}
}
With this workaround, I've the expected saved entith (with a correct JSON):
{
"id": 4,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": "Rectangle",
"color": "Red",
"dimension": 50
}
}
Is there an automatic method/annotation, with JPA or Spring or Hibernate, in order to have the "complete" persisted entity?
I would like to avoid to declare the EntityManager in every REST or Service class, or I want avoid to call the .findOne(Long) method everytime I want the new refreshed persisted entity.
Thanks a lot,
Andrea
解决方案 That's not enough:
Something result = somethingRepository.save(something);
You need to manually merge the incoming entity:
Something dbSomething = somethingRepository.findOne(
Something.class, something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
somethingRepository.save(dbSomething);
Since the property
attribute is using the default FetchType.EAGER
, the entity should have the property
attribute initialized.
But, that's strange to call the Repository twice from the REST controller. You should have a Service layer that does all that in a @Transactional
service method. That way, you don't need to resave the entity since it's already managed.
@Transactional
public Something mergeSomething(Something something) {
Something dbSomething = somethingRepository.findOne(
Something.class, something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
return dbSomething;
}
Now, you need to carefully merge every property you sent. In your case, if you send null
for property
you should decide whether you should nullify the @ManyToOne
reference or not. So, it depends on your current application business logic requirements.
Update
If you make sure you always send back the same entity you previously fetched, you could just use merge
.
em.refresh(result);
But your property
attribute is just an id, and not an actual child entity, so you have to resolve that yourself in the Service layer.
这篇关于保存后刷新并获取一个实体(JPA / Spring Data / Hibernate)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!