spring-boot - 无法使用 @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 探查器结果,实际发送给数据库的是什么。
解决方案
原来是数据库而不是插入触发器。
推荐阅读
- c# - 使用 Like 搜索数据库中的数据,可能具有不同的列值
- python - 无法使用 docker 设置 Kafka 和 Python
- node.js - 为什么我收到“发送到客户端后无法设置标题”错误,即使我在 1 个响应后使用了 return
- android - 颤动如何支持类似于android sdp的多种屏幕尺寸
- r - 如何从 selectInput() 函数中获取 2 个特定列的值作为列的标题并绘制这些列?
- macos - Jenkins-无法执行shell命令
- wcf - 无法使用服务引用调用 WCF 服务操作
- unity3d - 将实时摄像机源导入统一
- python - 如果余数不为 0,则删除行
- c# - 搜索文本格式,First Upper,Rest Lower