我有两个简单的实体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 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() +
"}";
}
属性:
@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() + "'" +
"}";
}
}
这是SomethingRepository
(Spring):
@SuppressWarnings("unused")
@Repository
public interface SomethingRepository extends JpaRepository<Something,Long> {
}
通过REST控制器和JSON,我想创建一个新的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;
}
}
这是输入中的JSON(property
id
1是数据库中的现有行):
{
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1
}
}
问题是:在方法.save(something)
之后,变量result
包含持久化实体,但没有字段property
的字段,已验证(它们是null
):
输出JSON:
{
"id": 1,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": null,
"color": null,
"dimension": null
}
}
我希望在保存操作后验证/返回它们。
为了解决这个问题,我必须在REST控制器中注入/声明EntityManager
,并调用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;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
em.refresh(result);
return result;
}
}
使用此解决方案,我得到了预期的保存实体(使用正确的JSON):
{
"id": 4,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": "Rectangle",
"color": "Red",
"dimension": 50
}
}
是否有JPA、Spring或Hibernate的自动方法/注解,以便拥有“完整”的持久化实体?
我希望避免在每个REST或Service类中声明EntityManager
,或者希望避免在每次需要新的刷新持久化实体时调用.findOne(Long)
方法。
5条答案
按热度按时间fwzugrvs1#
您可以通过创建一个CustomJpaRepository一次性定义
EntityManager
,而不是在每个resource中定义EntityManager
。参考然后直接在每个存储库中使用
EntityManager
的refresh
。请参考以下示例:
自定义存储库接口
自定义存储库实施
在Sping Boot 应用程序类中启用自定义JPARepository
您的信息库
直接在SomethingResource中使用Refresh(假设Something是实体)
c9qzyr3d2#
这还不够:
您需要手动合并传入实体:
由于
property
属性使用默认的FetchType.EAGER
,因此实体应初始化property
属性。但是,从REST控制器调用Repository两次是很奇怪的。你应该有一个服务层,它在
@Transactional
服务方法中完成所有这些工作。这样,你就不需要重新保存实体了,因为它已经被管理了。现在,您需要小心地合并发送的每个属性。在您的示例中,如果您发送
null
来替换property
,则应该决定是否应该使@ManyToOne
引用无效。因此,这取决于您当前的应用程序业务逻辑需求。更新
如果您确保总是返回先前获取的相同实体,则可以使用
merge
。但是您的
property
属性只是一个id,而不是一个实际的子实体,因此您必须在服务层中自己解决这个问题。cwdobuhd3#
在Sping Boot JpaRepository中:
如果我们的修改查询更改了持久性上下文中包含的实体,则此上下文将过时。
以便从数据库中提取具有最新记录的实体。
修改时使用(自动清除= true)
@Modifying注解具有clearAutomatically属性,该属性定义是否应在执行修改查询后清除基础持久性上下文。
示例:
beq87vna4#
我将用使用
session.load
生成的代理替换该属性现在,结果将从数据库中加载整个属性对象
hfyxw5xn5#
在持久化实体时,它将处于托管状态,因此,如果只调用
something.getProperty();
,它将从数据库加载并填充something
实体的property
值所以通常当你有多对一的关系时,应该自动获取。如果没有调用实体中对象的getter,也会通过触发一个新的DBFind请求来填充它们。