首页 > 解决方案 > CrudRepository - Hibernate - 用手动设置 id 覆盖现有模型

问题描述

我有一个问题,从现在开始我一直在尝试解决。

我必须使用 CrudRepository 和 Hibernate 在数据库中保存具有手动设置 ID 的模型。

但是id的手动设置总是被忽略。

是否有可能,强制

CrudRepository.save(模型 m)

用 UPDATE 持久化给定的模型?

查询总是产生 INSERT 语句,而不使用 id。

我必须手动执行此操作的原因是,标识符不是数据库 ID - 它是作为 UUID 在外部生成的 ID,在具有此模型条目的多个数据库中是唯一的。该模型通过 hazelcast-cluster 作为序列化对象共享。

举个例子:数据库已经包含一个 ID 为 1 的模型条目:

id    identifier_field_with_unique_constraint     a_changing_number
1     THIS_IS_THE_UNIQUE_STRING                   10

现在我需要更新它。我创建了一个新的模型版本

Model m = new Model();
m.setIdentifierFieldWithUniqueConstraint(THIS_IS_THE_UNIQUE_STRING);
m.setAChangingNumberField(20);
saveMe(m);

void saveMe(Model m) {
    Optional<Model> presentModalOpt = modelCrudRepo.findByIdentField(THIS_IS_THE_UNIQUE_STRING)
    if(presentModalOpt.isPresent()) {
        // The unique value in my identifier field exists in the database already
        // so use that id for the new model, so it will be overwritten
        m.setId(modalOpt.get().getId());
    } else {
        m.setId(null);
    }
    // This call will now do an INSERT, instead of UPDATE, 
    // even though the id is set in the model AND the id exists in the database!
    modelCrudRepo.save(m);
    // ConstraintViolationException for the unique identifier field.
    // It would be a duplicate now, which is not allowed, because it uses INSERT instead of UPDATE
}

id 字段使用@Id 和@GeneratedValue 注解进行标记(对于id 为null 并且应该生成id 的情况)

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

我什至尝试将此字段仅更改为没有@GeneratedValue 的@Id 字段,并始终自行生成ID。它没有效果,它总是使用 INSERT 语句,从不 UPDATE。

我究竟做错了什么?

除了 id 之外,CrudRepository 是否有另一个标识符将模型声明为现有模型?

我很高兴得到任何帮助。

标签: javahibernatecrud-repository

解决方案


CrudRepository 只有 save 方法,但它既可以用于插入,也可以用于更新。

  1. 当您保存具有空 id 的实体时,它将进行保存。
  2. 当您使用现有 ID 保存实体时,它会进行更新,这意味着在您使用 findById 并更改对象中的某些内容后,您可以在此对象上调用 save 并且它实际上会进行更新,因为在 findById 之后您会得到一个您的数据库中存在的具有填充 id 的对象。

在您的情况下,您正在根据字段(唯一)获取记录但是只有当模型对象具有现有的主键值时,记录才会更新

在您的代码中应该有presentModalOpt而不是modalOpt

void saveMe(Model m) {
    Optional<Model> presentModalOpt = modelCrudRepo.findByIdentField(THIS_IS_THE_UNIQUE_STRING)
    if(presentModalOpt.isPresent()) {  // should be presentModalOpt instead of modalOpt
 
    } else {
        m.setId(null);
    }
    modelCrudRepo.save(m);
    
}

查看默认实现 -

/*
 * (non-Javadoc)
 * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
 */
@Transactional
public <S extends T> S save(S entity) {

     if (entityInformation.isNew(entity)) {
          em.persist(entity);
          return entity;
     } else {
          return em.merge(entity);
     }
}

推荐阅读