복붙노트

[SPRING] 기본 키의 일부가 외래 키인 JPA에서 복합 기본 키를 매핑하는 방법

SPRING

기본 키의 일부가 외래 키인 JPA에서 복합 기본 키를 매핑하는 방법

내 장치에서 작동하는 데이터를 얻기 위해 JPA Entity Bean을 빌드하는 방법을 파악하려고합니다. 데이터베이스가 오래되었고 돌이므로 스키마를 변경할 수 없습니다. 장치 모델에는 복합 기본 키가 있습니다. 열 중 하나는 FK에서 장치 유형입니다.

나는 두 가지 다른 것을 시도했다. 먼저 Device에는 DeviceModel과 DeviceType이 있지만 dev_type을 참조하는 오류가 너무 많습니다. 그래서 DeviceModel에 DeviceType에 대한 참조가 있었지만 동일한 오류가 발생했습니다.

도움이된다면, Spring Data 4.2.x와 Hibernate 4.3.8을 사용하고 있습니다.

JPA에서 복합 기본 키를 생성하고 처리하는 방법과 같이 온라인에서 찾은 다른 대답은 기본 데이터 유형에만 매핑되므로 도움이되지 않습니다. 사실, 위의 대답은 아래 코드에서 구현됩니다 ...하지만 한 단계 더 나아갈 필요가 있습니다.

스키마 :

create table devices
(
  device_nbr serial(1),
  device_id nchar(20) not null unique,
  dev_type integer not null,
  model_nbr integer default 1,
  unit_addr nchar(32),
  primary key (device_nbr),
  foreign key (dev_type) references devtypes (dev_type),
  foreign key (dev_type, model_nbr) references devmodels (dev_type, model_nbr)
);

create table devmodels
(
  dev_type      integer  not null,
  model_nbr     integer  not null,
  model_desc    nchar(20),
  primary key (dev_type, model_nbr),
  foreign key (dev_type) references devtypes (dev_type)
);

create table devtypes
(
  dev_type integer not null,
  dev_desc nchar(16) not null unique,
  primary key (dev_type)
);

지금까지의 My Beans (DeviceType을 Device 또는 DeviceModel에 묶지 않아야합니다.)

@Entity
@Table(name = "devices")
public class Device
{
    @Id
    @GeneratedValue
    @Column(name = "device_nbr")
    private Long                number;

    @Column(name = "device_id", length = 30)
    private String          id;

    @Column(name = "unit_addr", length = 30)
    private String          unitAddress;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns({
        @JoinColumn(name = "dev_type"),
        @JoinColumn(name = "model_nbr")
    })
    private DeviceModel deviceModel;

...Getters and setters
}

public class DeviceModelPK implements Serializable
{
    private static final long   serialVersionUID    = -8173857210615808268L;
    protected Integer                   deviceTypeNumber;
    protected Integer                   modelNumber;

...Getters and setters
}

@Entity
@Table(name = "devmodels")
@IdClass(DeviceModelPK.class)
public class DeviceModel
{
    @Id
    @Column(name = "dev_type")
    private Integer         deviceTypeNumber;

    @Id
    @Column(name = "model_nbr")
    private Integer         modelNumber;

    @Column(name = "model_desc")
    private String          description;

...Getters and setters
}

@Entity
@Table(name = "devtypes")
public class DeviceType
{
    @Id
    @GeneratedValue
    @Column(name = "dev_type")
    private Integer number;

    @Column(name = "dev_desc", length = 30)
    private String  description;

...Getters and setters
}

해결법

  1. ==============================

    1.문제는 엔티티 대신 컬럼의 관점에서 생각하는 것이지만 문제는 다소 까다 롭습니다. 기본적인 질문은 Entity를 Composite Key의 일부로 포함시키는 방법이며, 여기에서 대답을 찾았습니다. JPA에서 @EmbeddedId로 @ManyToOne 속성을 포함하는 복합 기본 키를 만드는 방법. 장치:

    문제는 엔티티 대신 컬럼의 관점에서 생각하는 것이지만 문제는 다소 까다 롭습니다. 기본적인 질문은 Entity를 Composite Key의 일부로 포함시키는 방법이며, 여기에서 대답을 찾았습니다. JPA에서 @EmbeddedId로 @ManyToOne 속성을 포함하는 복합 기본 키를 만드는 방법. 장치:

    @Entity
    @Table(name = "devices")
    public class Device
    {
        @Id
        @Column(name = "device_nbr")
        private Long number;
    
        @Column(name = "device_id", length = 20)
        private String deviceId;
    
        @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
        @JoinColumns({@JoinColumn(name="dev_type", referencedColumnName="dev_type"), @JoinColumn(name="model_nbr", referencedColumnName="model_nbr")})
        private DeviceModel deviceModel;
    
        // This creates a foreign key constraint, but otherwise doesn't function
        // deviceType must be accessed through deviceModel
        // note, it can be used for explicit selects, e.g., "select d.deviceType from Device d"
        @OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
        @JoinColumn(name="dev_type", referencedColumnName="dev_type", insertable=false, updatable=false)
        private DeviceType deviceType;
    
        @Column(name = "unit_addr", length = 32)
        private String unitAddress;
    

    DeviceModel :

    @Entity
    @Table(name = "devmodels")
    public class DeviceModel
    {
        @EmbeddedId
        private DeviceModelId id;
    
        @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
        @JoinColumn(name="dev_type")
        @MapsId("deviceType")
        private DeviceType deviceType;
    
        @Column(name = "model_desc", length=20)
        private String  description;
    

    DeviceModelId :

    @Embeddable
    public class DeviceModelId implements Serializable
    {
        private static final long   serialVersionUID    = -8173857210615808268L;
        private Integer deviceType;
        @Column(name="model_nbr")
        private Integer modelNumber;
    

    @Embeddable과 @EmbeddedId를 사용했음을 주목하십시오. 그것은 단지 최신이며 JPA 공급자 주석이 @IdClass보다 선호 될 것이라는 의견을 읽었습니다. 나는 컬럼 이름을 조금 더 쉽게 만들었다 고 생각하지만 기억이 안납니다.

    기기 종류:

    @Entity
    @Table(name = "devtypes")
    public class DeviceType
    {
        @Id
        @GeneratedValue
        @Column(name = "dev_type")
        private Integer deviceType;
    
        @Column(name = "dev_desc", length = 16)
        private String  description;
    

    트릭은 DeviceModel의 @MapsId입니다. 이로써 CompositeKey에서 엔티티의 사용이 가능해졌습니다. 해당 필드의 @JoinColumn이 해당 필드의 이름을 사용할 수있게했습니다. 이를 사용하는 유일한 방법은 수동으로 DeviceTypeId를 만드는 것입니다.

    DeviceModel model = new DeviceModel();
    DeviceModelId modelId = new DeviceModelId();
    modelId.setModelNumber(654321);
    // have to have a DeviceType to create a DeviceModel
    model.setDeviceType(type);
    model.setId(modelId);
    

    이렇게하면 다음과 같은 스키마가 만들어지며 이는 사용자의 것과 같습니다.

    create table devices (device_nbr bigint not null, device_id varchar(20), unit_addr varchar(32), dev_type integer, model_nbr integer, primary key (device_nbr))
    create table devmodels (dev_type integer not null, model_nbr integer not null, model_desc varchar(20), primary key (dev_type, model_nbr))
    create table devtypes (dev_type integer not null, dev_desc varchar(16), primary key (dev_type))
    alter table devices add constraint FK8q0a886v04gg0qv261x1b2qrf foreign key (dev_type, model_nbr) references devmodels
    alter table devices add constraint FKb72a7hq5phwjtbhaglobdkgji foreign key (dev_type) references devtypes
    alter table devmodels add constraint FK4xlwyd2gwpbs4g4hdckyb11oj foreign key (dev_type) references devtypes
    
  2. from https://stackoverflow.com/questions/36338527/how-to-map-compound-primary-key-in-jpa-where-part-of-primary-key-is-a-foreign-k by cc-by-sa and MIT license