java - @EmbeddedId 和 @Embeddable 中的 @GenerateValue

标签 java mysql hibernate jpa orm

我有一个具有以下结构的 MySQL 数据库(摘录):

CREATE TABLE MENU(
    id_menu    TINYINT      UNSIGNED    NOT NULL    AUTO_INCREMENT,
    name       VARCHAR(50)              NOT NULL,
    PRIMARY KEY (id_menu)
);

CREATE TABLE OPERATION(
    id_operation    SMALLINT        UNSIGNED    NOT NULL    AUTO_INCREMENT,
    id_menu         TINYINT         UNSIGNED    NOT NULL,
    operation       VARCHAR(50)                 NOT NULL,
    url             VARCHAR(100)                NOT NULL,
    PRIMARY KEY (id_operation, id_menu)
);

CREATE TABLE operation_role(
    id_operation    SMALLINT    UNSIGNED    NOT NULL,
    id_menu         TINYINT     UNSIGNED    NOT NULL,
    role            CHAR(15)                NOT NULL,
    id_user         BIGINT      UNSIGNED    NOT NULL,
   PRIMARY KEY (id_operation, id_menu, role, id_user)
);

CREATE TABLE role_user(
    role          CHAR(15)              NOT NULL
    id_user       BIGINT      UNSIGNED  NOT NULL,
    PRIMARY KEY (role, id_user)
);

-- RELATIONSHIPS

-- 
-- TABLE: OPERATION 
-- Meaning: a MENU has several OPERATION (One to Many relationship)
ALTER TABLE OPERACION ADD CONSTRAINT fk_menu_operacion 
    FOREIGN KEY (id_menu)
    REFERENCES MENU(id_menu);

-- 
-- TABLE: operation_rol 
-- This is the join table for the Many to Many relatioship OPERATION-role_user
ALTER TABLE operation_role ADD CONSTRAINT fk_operation_oprole 
    FOREIGN KEY (id_operation, id_menu)
    REFERENCES OPERATION(id_operation, id_menu);

ALTER TABLE operaciones_rol ADD CONSTRAINT fk_roles_operation 
    FOREIGN KEY (role, id_user)
    REFERENCES role_user(role, id_user);

-- 
-- TABLE: roles_usuario 
-- Meaning: a user can have several roles (One to Many)
ALTER TABLE roles_usuario ADD CONSTRAINT fk_usuario_roles 
    FOREIGN KEY (id_usuario)
    REFERENCES USUARIO(id_usuario);

此外,还有一个 USER 表,但这并不重要,通过这些表您可以全面了解问题。

如您所见,某些列具有 AUTO_INCRMENT 属性,该属性将在 @Entity 中变为 @GenerateValue(strategy = GenerationType.IDENTITY)类。

OPERATIONrole_user 由于它们与其他表的关系而具有复合主键,因此我无法更改它。由于复合 PK,映射的类必须具有 @EmbeddedId 以及相应的 @Embeddable 类。

问题是我需要在复合PK“native”部分中使用@GenerateValue,例如:OPERATION .id_operation 必须具有 @GenerateValueOPERATION.id_menu 是从 MENU.id_menu 传播的,但JPA不支持@GenerateValue@EmbeddedId`中。我是否正确地解释了情况?

我尝试使用 NetBeans 的“来自 DataBase 的实体类”选项的“建议”,但使用简单的方法为表生成了 @GenerateValue 注释列的标识符(如 MENU),但不是复合的标识符(如 OPERATION)。

所以问题是我该如何进行映射?。更改数据库的结构不是一种选择,而是由于业务需求而这样做的。

感谢任何帮助或指导。提前非常感谢您。

最佳答案

您的 JPA @Id 不需要与数据库 PK 列匹配。只要它是唯一的,那么这就是最重要的,并且由于关联的列是自动增量列,那么情况就是如此。

来自https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing :

The JPA Id does not always have to match the database table primary key constraint, nor is a primary key or a unique constraint required.

因此,虽然关联表的 PK 可以配置为 PRIMARY KEY (id_operation, id_menu) ,但是 id_operation 通过自动递增,可以独立作为 PK,因此操作可以映射如下:

@Entity
public class Operation{

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

    @ManyToOne
    @JoinColumn(name = "id_menu")
    private Menu menu;
}

如果您创建相关的IDClass,则OperationRole可以映射如下。有关此场景的示例以及 ID 类的外观,请参见:

https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Example_JPA_2.0_ManyToOne_id_annotation

@Entity
@IdClass(OperationRolePk.class)
public class OperationRole{

        @Id
        @ManyToOne
        @JoinColumn(name = "id_operation")
        private Operation operation;

        @Id
        @ManyToOne
        @JoinColumn(name = "id_menu")
        private Menu menu;

        @Id
        @ManyToOne
        @JoinColumn(name = "id_user")
        private User user;
}

关于java - @EmbeddedId 和 @Embeddable 中的 @GenerateValue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37448621/

相关文章:

java - 如何防止对 System.exit() 的调用终止 JVM?

MySql 备份/变更监控

java - 如何根据时区在mysql中存储时间戳?

javax.servlet.ServletException : Error creating bean - Invocation of init method failed; nested exception is javax. 持久性.PersistenceException

java - 如何相对于子目录运行 Jenkins 管道?

java - 文件输出/输入异常

php - 比 get_headers() 更快的东西

java - 如何正确使用 UUID 作为我的 @Entity 的 @Id?

mysql - 使用 CrudRepository 持久化 JPA 实体

java - shutdown() 之后需要 ExecutorService.awaitTermination()