使用共享主键持久保存 @OneToOne 关系时出现 IdentifierGenerationException

问题描述 投票:0回答:1

我正在使用 MySQL 数据库并使用 Hibernate (6.6.0.Final),而不使用 Spring。我的架构涉及两个表,

film
film_text
,它们以一对一关系隐式相关。
film
表有一个生成的主键 (
film_id
),我希望将此键与
film_text
表共享作为其主键。

逻辑关系是这样的:

Film
实体知道其对应的
Text
实体,但
Text
不保留对
Film
的引用。这是我的表格的结构:

DDL

film

CREATE TABLE `film` (
  `film_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(128) NOT NULL,
  `description` text,
  `release_year` year DEFAULT NULL,
  `language_id` tinyint unsigned NOT NULL,
  `original_language_id` tinyint unsigned DEFAULT NULL,
  `rental_duration` tinyint unsigned NOT NULL DEFAULT '3',
  `rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
  `length` smallint unsigned DEFAULT NULL,
  `replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
  `rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
  `special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`film_id`),
  KEY `idx_fk_language_id` (`language_id`),
  KEY `idx_fk_original_language_id` (`original_language_id`),
  CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

DDL

film_text

CREATE TABLE `film_text` (
  `film_id` smallint NOT NULL,
  `title` varchar(255) NOT NULL,
  `description` text,
  PRIMARY KEY (`film_id`),
  FULLTEXT KEY `idx_title_description` (`title`, `description`)
) ENGINE=InnoDB;

在我的 Hibernate 模型中,我使用

@MapsId
注释来确保
Text
实体重用关联的
Film
的主键。这是我的实体的代码:

Film
实体:

@Entity
@Table(schema = "movie", name = "film")
@Getter
@Setter
@NoArgsConstructor
@RequiredArgsConstructor
public class Film {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "film_id")
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @MapsId
    @JoinColumn(name = "film_id", nullable = false)
    @NonNull
    private Text text;

    // other fields and relationships
}

Text
实体:

@Entity
@Table(schema = "movie", name = "film_text")
@Getter
@Setter
@NoArgsConstructor
@RequiredArgsConstructor
public class Text {
    @Id
    @Column(name = "film_id")
    @Setter(AccessLevel.NONE)
    private Integer id;

    @Column(nullable = false)
    @NonNull
    private String title;

    @Column(length = 65_535)
    private String description;
}

当我尝试持久化

Film
实体(它应该级联
Text
的持久化)时,我遇到以下错误:

Identifier of entity 'Text' must be manually assigned before calling 'persist()'
org.hibernate.id.IdentifierGenerationException: Identifier of entity 'Text' must be manually assigned before calling 'persist()'

预期行为:

我希望当我持久化一个

Film
实体时,Hibernate 应该为
film
实体生成一个 ID,并自动将该 ID 分配给关联的
Text
实体(因为它们共享相同的主键)。

我尝试过的:

  1. 我已经在
    @MapsId
    实体中设置了
    Film
    ,它应该将
    Film
    的主键映射到
    Text
  2. 我已确保级联已正确配置
    CascadeType.ALL
  3. 我使用
    @JoinColumn
    来确保两个实体中
    film_id
    列之间的正确映射。

问题:

为什么 Hibernate 在

film_id
操作期间不自动将
Film
Text
分配给
persist()
,我该如何解决这个
IdentifierGenerationException
?我的实体映射中是否缺少某些内容,可以让 ID 在两个实体之间正确共享?

任何见解或建议将不胜感激!

java hibernate jpa hibernate-annotations
1个回答
0
投票

您的关系倒退,并且滥用了 MapsId 注释。您希望该注释位于“另一”侧,即 Text->Film 关系上,因为它告诉 JPA 此关系(及其 FK 列)控制注释中指定的 ID 列/属性。更多这样的:

@Entity
public class Film {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "film_id")
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @NonNull
    private Text text;

    // other fields and relationships
}

@Entity
public class Text {
    @Id
    @Column(name = "film_id")
    private Integer id;
    @MapsId
    @JoinColumn(name = "film_id")
    Film film;
    // other fields and relationships

}

您也可以在文本中不使用 Integer id 属性,因为 JPA 允许将关系标记为 ID:

@Entity
public class Text {
    @Id
    @JoinColumn(name = "film_id")
    Film film;
    // other fields and relationships
}
© www.soinside.com 2019 - 2024. All rights reserved.