首页 > 解决方案 > 无法使用 @GeneratedValue(IDENTITY) 和双向 @OneToMany 将对象保存到数据库

问题描述

我在持久化和级联两个实体时遇到了麻烦,这两个实体都具有生成的 ID。

数据库表

CREATE TABLE [dbo].[CISLO](
    [ID_CISLA] [bigint] IDENTITY(1,1) NOT NULL,
        constraint PK_CISLO primary key (ID_CISLA)
        ...omit other columns for brevity

此表的行为就像绑定表一样 - 它将数字连接到堆栈

CREATE TABLE [dbo].[VAZBA_ZASOBNIK_CISLO](
    [ID_VAZBY_ZASOBNIK_CISLO] [bigint] IDENTITY(1,1) NOT NULL,
    [ID_ZASOBNIKU] [int] NOT NULL,
    [ID_CISLA] [bigint] NOT NULL,
        constraint PK_VAZBA_ZASOBNIK_CISLO primary key (ID_VAZBY_ZASOBNIK_CISLO)
    ...omit other columns for brevity

CREATE TABLE [dbo].[ZASOBNIK](
    [ID_ZASOBNIKU] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
        constraint PK_ZASOBNIK primary key (ID_ZASOBNIKU)
        ...omit other columns for brevity

实体看起来像这样

@Getter
@Setter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)

@Entity
public class Cislo extends AbstractBaseEntity<Cislo, Long> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long idCisla;

    @ToString.Exclude
    @Setter(AccessLevel.NONE)
    @OneToMany(mappedBy = "cislo", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    private Collection<VazbaZasobnikCislo> numberStackRelations = new LinkedList<>();

@Getter
@Setter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class VazbaZasobnikCislo extends AbstractBaseEntity<VazbaZasobnikCislo, Long> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long idVazbyZasobnikCislo;

    @NotNull
    @ToString.Exclude
    @JoinColumn(name = "ID_ZASOBNIKU")
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Zasobnik zasobnik;

    @NotNull
    @ToString.Exclude
    @JoinColumn(name = "ID_CISLA")
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Cislo cislo;
}

@Getter
@Setter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)

@Entity
public class Zasobnik extends AbstractBaseEntity<Zasobnik, Integer> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer idZasobniku;

    @ToString.Exclude
    @Setter(AccessLevel.NONE)
    @OneToMany(mappedBy = "zasobnik", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    private Collection<VazbaZasobnikCislo> numberStackRelations = new LinkedList<>();

现在程序部分

我正在尝试创建数字(Cislo)并通过创建数字堆栈关系(VazbaZasobnikCislo)将其链接到现有堆栈(Zasobnik)。整个块使用spring的@Transactional(禁用打开视图)在事务会话中运行。“堆栈”变量是持久实体 Zasobnik。"asNew" 只是为 Persistable 接口设置标志 isNew(这一次可能由于 id 生成而不必要)。

var number = new Cislo(purpose, remainingRange.getFrom(), false, false, false);
var numberStackRelation = VazbaZasobnikCislo.initialize("CISRAD", stack, number.asNew());
vazbaZasobnikCisloService.save(numberStackRelation.asNew());

VazbaZasobnikCislo.initialize 使其他关系保持同步。

private VazbaZasobnikCislo(String autorZmeny, Zasobnik zasobnik, Cislo cislo) {
    this.zasobnik = zasobnik;
    this.cislo = cislo;
    this.auditAttributes = new AuditAttributes(autorZmeny);
}

public static VazbaZasobnikCislo initialize(String autorZmeny, Zasobnik stack, Cislo number) {
    var stackNumberRelation = new VazbaZasobnikCislo(autorZmeny, stack, number);
    stack.getNumberStackRelations().add(stackNumberRelation);
    number.getNumberStackRelations().add(stackNumberRelation);
    return stackNumberRelation;
}

以下代码生成此 sql:

Hibernate:
    insert
    into
        CISLO
        (CERPANO_V_CILOVEM_SYSTEMU_AN, DATUM_ZARAZENI_BLACKLIST, DATUM_ZMENY, HODNOTA_CISLA, NEOPRAVNENE_POUZITI_AN, POUZITE_AN, ID_UCELU)
    values
        (?, ?, ?, ?, ?, ?, ?) select
            scope_identity()
Hibernate:
    insert
    into
        VAZBA_ZASOBNIK_CISLO
        (AUTOR_ZMENY, DATUM_ZMENY, ID_CISLA, ID_UZIVATELE_KOMU_PRIDELENO, POPIS, ID_POZADAVKU, ID_UCTU_KOMU_PRIDELENO, ID_ZASOBNIKU)
    values
        (?, ?, ?, ?, ?, ?, ?, ?) select
            scope_identity()
2021-06-10 14:40:23.158  WARN 61377 --- [nio-8087-exec-6] o.h.e.j.s.SqlExceptionHelper             : SQL Error: 547, SQLState: 23000
2021-06-10 14:40:23.161 ERROR 61377 --- [nio-8087-exec-6] o.h.e.j.s.SqlExceptionHelper             : Příkaz INSERT způsobil konflikt s omezením FOREIGN KEY s názvem FK_VAZBA_ZA_R_VAZBA_C_CISLO. Ke konfliktu došlo v databázi CISRAD_KOOP, tabulce dbo.CISLO, , column 'ID_CISLA'.

FK_VAZBA_ZA_R_VAZBA_C_CISLO定义如下:

在更新级联时更改表 VAZBA_ZASOBNIK_CISLO 添加约束 FK_VAZBA_ZA_R_VAZBA_C_CISLO 外键 (ID_CISLA) 引用 CISLO (ID_CISLA)

如果您需要更多信息,请告诉我。我将提供捕获的 SQL 探查器结果,实际发送给数据库的是什么。

标签: spring-boothibernate

解决方案


原来是数据库而不是插入触发器。


推荐阅读