【问题标题】:Update an entity and only overwrite non-null values (without a dynamic query)更新实体并仅覆盖非空值(没有动态查询)
【发布时间】:2019-05-12 17:11:33
【问题描述】:

我想通过将该实体的“不完整”实例交给JpaRepository 来更新现有实体。不完整的意思是只设置了我想要更改的值,其他值是null。现在,如果我这样做,所有null 值也将保存为null,因此会覆盖我想要保留的值。

我考虑过先从数据库中加载实体,然后以某种方式将更改合并到加载的对象中并再次保存,但必须有更好的方法。

我的实体:

@Entity
@Table
public class Location {

    @Id
    @NotNull
    @Type(type = "uuid-char")
    private UUID id = UUID.randomUUID();

    @Column
    @NotEmpty
    private String title;

    @Column
    @NotEmpty
    private String description;
...

我的仓库:

@Repository
public interface LocationRepository extends JpaRepository<Location, UUID>, LocationFilterFragment, JpaSpecificationExecutor {

    Optional<Location> findLocationById(UUID id);
...

顺便说一句,我使用标准的repo.save(location) 方法。

更新:一种方法是使用动态查询/条件查询,但我正在寻找更方便且不易出错的方法。

这足以告诉我正确的方向,因为我不知道要寻找什么。提前致谢!

【问题讨论】:

  • 你更新了多少字段?
  • 我希望它是动态的。例如,如果我只想更新标题,我将标题设置为新值,并在 null 上设置其他值。或者,如果我也想更新描述,我也将其设置为非空值。当然 ID 除外。
  • 在您编写查询之前,我不确定您是否可以动态执行此类操作
  • 这对我来说似乎很明显,必须有一个更简单的方法。 :D
  • 你可以等到有人发布最佳答案

标签: java hibernate jpa spring-data-jpa spring-data


【解决方案1】:

我的第一种方法是:不要合并不完整的对象。如果您在存储库上调用 save(转换为 entityManager 上的 merge),Hibernate 会将其视为当前状态,并将更新所有值。

我将继续以下操作:

  • 通过 id 找到要更改的实体
  • 通过从“不完整对象”复制要更改的值来设置它们

请记住,这两个步骤必须在一个事务中执行。退出事务范围时,hibernate 将依赖其脏检查机制并更新实体(不需要merge 调用)在这种方法中,您的“不完整对象”不必是实体,它永远不会被持久化。

请注意,默认情况下,所有字段都将在更新查询中发送(但现在未更改的字段不为空,它们反映了 dB 的先前状态)如果您只想将脏字段作为查询的一部分,请了解@DynamicUpdate

另一个注意事项:如果您执行自定义 jpql 或标准 API 更新,您将受益于未执行的选择。不利的一面是,Hibernate 不知道这些更改,也不会更新其缓存。

【讨论】:

  • 感谢您的回答!你知道我如何“通过从你的“不完整对象”复制它们来设置你想要更改的值”,而无需 if/else 每个属性并手动设置它?
  • 坦率地说,我想到的一切要么过度设计,要么牺牲了类型安全。不过,它值得一个单独的问题。
  • 如果您的“不完整对象”来自某个控制器,那么它已经通过反射创建,所以也许遵循它并不是那么糟糕。我记得在一个项目中使用过 JPA 元模型,但我不愿意将它推荐给您的案例(因为过度设计)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 2022-08-11
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
相关资源
最近更新 更多