告诉Hibernate仅在数据库为空时让数据库生成一个值

时间:2019-05-19 16:58:21

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

我正在为REST-API实现PUT方法。 我有一个类似于以下内容的POJO:

public class Brand implements Serializable {
    @Column(columnDefinition = "serial")
    @Generated(GenerationTime.INSERT)
    @JsonIgnore
    private Integer id;

    @Id
    @JsonProperty("brand")
    private String brand;
    .
    .
    .
}

在postgresql数据库中,brand表具有以下列:

  • 外部不可见的数据库内部ID(SERIAL)。(用于连接表)
  • 作为主键的品牌(TEXT)

我的服务方法如下:

public Brand updateBrand(String brand, Brand update) {
    Brand b = brandRepository.findBrandByBrand(brand);
    if(b == null) { //If not exists create new one
        b = new Brand(null, brand);
    }
    else {  //If exists keep id, delete old one and create new entry
        if(update != null && update.getBrand() != null) {
            brandRepository.delete(b);
        }
        ServiceUtils.copyProperties(update, b); //This is within the if clause, because brand is the only value
    }
    return brandRepository.save(b);
}

控制器将具有以下内容:

@PutMapping(value = "/brand/{brand}")
public ResponseEntity<Brand> updateBrand(@PathVariable("brand") String brand,
                                         @RequestBody Brand update) {
    Brand updated = articleNumberService.updateBrand(brand, update);
    if(updated == null) {
        throw new EntryCreationFailedException(brand); //self made exception
    }
    return new ResponseEntity<>(updated, HttpStatus.OK);
}

现在我的以下问题是,在调用PUT ../brand/stackoverflow时 与身体:

{"brand":"StackOverflow")

它将删除旧的stackoverflow品牌(例如,其id = 1),并创建一个新的StackOverflow品牌。但是在检查数据库时,id列会增加(因此现在id为2)。 我检查了一下,这是由于休眠状态仍然导致的:

insert 
    into
        brand
        (brand) 
    values
        (?)

当id为null时,这就是我想要的。例如,在创建新品牌时会发生这种情况。但是,当仅覆盖品牌和ID不为null时,我想让休眠模式调用此方法:

insert 
    into
        brand
        (id, brand) 
    values
        (?, ?)

我知道可以通过创建自己的保存方法并在紧急情况下覆盖查询来实现。但是,我很乐观,如果没有这种情况,那将是可能的。但是我真的找不到合适的答案。我已经无法找到针对Postgresql特定串行行为的正确注释。

P.S:我知道有些人会喊“为什么将Brand作为主键而不是ID!”但这只是数据库的简单类/部分。还有更复杂的类,它们对内部数据库ID使用完全相同的方式(并且实际上需要),但是具有多个主键等。因此,这是我的问题的非常简单的表示形式。

2 个答案:

答案 0 :(得分:0)

由于Postgres使用序列号作为auto_increment,因此在sql语句中不包含id插入。在幕后,它为其创建序列。因此,您应该为其使用Generation类型IDENTITY。

答案 1 :(得分:0)

如果这是一个带有<%= f.options_for_select(@projects, object.id) %>的字段,则可以编写一个自定义@Id,如果该值为null,则该自定义@GenericGenerator会获取序列,但由于它不是主键,我想您会不得不拥有一个单独的父实体及其自己的生成ID。