简体   繁体   中英

Hibernate composite key with composite key

I'm currently mapping a complex database schema wqith HIbernate and I have hit a wall with an entity which has a composite key with another composite key.

I have this table for roles with a composite key (site_id, id)

CREATE TABLE IF NOT EXISTS core.roles
(
    id uuid NOT NULL DEFAULT gen_random_uuid(),
    name character varying(100) NOT NULL,
    is_system_role boolean NOT NULL DEFAULT FALSE,
    site_id uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    updated_at timestamp with time zone NOT NULL DEFAULT now(),
    created_by uuid NOT NULL,
    updated_by uuid NOT NULL,
    CONSTRAINT roles_pkey PRIMARY KEY (site_id, id),
    CONSTRAINT roles_name_key UNIQUE (site_id, name),
    CONSTRAINT roles_site_id_fkey FOREIGN KEY (site_id)
        REFERENCES core.sites (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT roles_created_by_fkey FOREIGN KEY (created_by)
        REFERENCES core.users (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE RESTRICT,
    CONSTRAINT roles_updated_by_fkey FOREIGN KEY (updated_by)
        REFERENCES core.users (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE RESTRICT
);

And I have this table with a composite key which also uses the previous one.

CREATE TABLE IF NOT EXISTS core.user_site_roles
(
    user_id uuid NOT NULL,
    site_id uuid NOT NULL,
    role_id uuid NOT NULL,
    created_at timestamp with time zone NOT NULL DEFAULT now(),
    created_by uuid NOT NULL,
    CONSTRAINT user_site_roles_pkey PRIMARY KEY (site_id, user_id, role_id),
    CONSTRAINT user_site_roles_site_id_fkey FOREIGN KEY (site_id)
        REFERENCES core.sites (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT user_site_roles_role_id_fkey FOREIGN KEY (site_id, role_id)
        REFERENCES core.roles (site_id, id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT user_site_roles_user_id_fkey FOREIGN KEY (user_id)
        REFERENCES core.users (id) MATCH SIMPLE
        ON UPDATE NO ACTION
   
    CONSTRAINT user_site_roles_created_by_fkey FOREIGN KEY (created_by)
        REFERENCES core.users (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE RESTRICT
);

My current mapping for the roles one which is working is:

@Embeddable
public class CommonId implements Serializable {

    @Type(type = "pg-id-uuid")
    @Column(columnDefinition = "uuid", updatable = false)
    private UUID id;

    @Type(type = "pg-id-uuid")
    @Column(name = "site_id", columnDefinition = "uuid", updatable = false)
    private UUID siteId;
}

@Entity
@Table(name = "roles", schema = "core")
@Data
@TypeDefs({
        @TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class Role extends AuditAtBy implements Serializable {

    @EmbeddedId
    private CommonId roleId;

    @ManyToOne
    @MapsId("siteId")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Site site;

    @Column(nullable = false, unique = true, length = 100)
    private String name;

    @Column(name = "is_system_role", nullable = false)
    private boolean isSystemRole;

}

I was trying something similar with the composite Key for the UserSiteRole but Hibernate tells me that it needs to columns to map the roleId when in the table I have just the id but the PK is form by the two values as you can see in the script, not sure how to map it to be honest.

@Embeddable
public class UserSiteRoleId implements Serializable {

    @Type(type = "pg-id-uuid")
    @Column(columnDefinition = "uuid", updatable = false)
    private UUID userId;

    @Type(type = "pg-id-uuid")
    @Column(name = "site_id", columnDefinition = "uuid", updatable = false)
    private UUID siteId;

    @Type(type = "pg-id-uuid")
    @Column(name = "role_id", columnDefinition = "uuid", updatable = false)
    private UUID roleId;
}

@Entity
@Table(name = "user_site_roles", schema = "core")
@Data
@TypeDefs({
        @TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class UserSiteRole extends AuditCreated implements Serializable {

    @EmbeddedId
    private UserSiteRoleId userSiteRoleId;

    @ManyToOne
    @MapsId("userId")
    @JoinColumn(name = "user_id", columnDefinition = "uuid", nullable = false)
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private User user;

    @ManyToOne
    @MapsId("siteId")
    @JoinColumn(name = "site_id", columnDefinition = "uuid", nullable = false)
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Site site;

    @ManyToOne
    @MapsId("roleId")
    @JoinColumn(name = "role_id", columnDefinition = "uuid", nullable = false)
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Role role;

}

I would appreciate any ideas about how to map it, I had never had to map such a complex relationship so not sure how to proceed in this case.

Does this answer your question? jpa hibernate composite foreign key mapping

Actually that was useful as it made it clear that we could change the mapping from embeddedId to IdClass and make it work.

This is our new IdClass, pretty simple:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserSiteRoleId implements Serializable {

    private User user;
    private Site site;
    private Role role;
}

And the entity itself working just inf e is as follows.

@Entity
@Table(name = "user_site_roles", schema = "core")
@Data
@TypeDefs({
        @TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
@IdClass(UserSiteRoleId.class)
public class UserSiteRole extends AuditCreated implements Serializable {

    @Id
    @ManyToOne
    @JoinColumn(name = "user_id", columnDefinition = "uuid", nullable = false)
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private User user;

    @Id
    @ManyToOne
    @JoinColumn(name = "site_id", columnDefinition = "uuid", nullable = false)
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Site site;

    @Id
    @ManyToOne
    @JoinColumns({
            @JoinColumn(name = "role_id", referencedColumnName="id", columnDefinition = "uuid", insertable = false, updatable = false),
            @JoinColumn(name = "site_id", referencedColumnName="site_id", columnDefinition = "uuid", insertable = false, updatable = false)
    })
    @Type(type = "pg-id-uuid")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Role role;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM