如何在JPA中映射复合主键,其中主键的一部分是外键

我试图弄清楚如何构建JPA实体bean,以使数据适用于我的设备。该数据库是旧的,一成不变的,所以我不能更改架构。设备模型具有复合主键,其中的一列是设备类型的FK。

我尝试了几种不同的方法。首先是设备具有DeviceModel和DeviceType,但是这给了我一个错误,那就是太多的东西在引用dev_type。因此,然后我尝试让DeviceModel引用DeviceType,但遇到了相同的错误。

如果有帮助/问题,我正在使用Spring Data 4.2.x和Hibernate 4.3.8.Final来备份所有内容。

我在网上找到的其他答案对我没有帮助,因为它们仅映射到基本数据类型。实际上,上面的答案是在下面的代码中实现的…但是我需要再上一级。

架构:

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)

);

到目前为止,我的Bean(它们不会将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

}

回答:

嗯,您遇到的基本问题是根据列而不是实体进行思考,尽管由于问题有点棘手,所以这可能是不公平的陈述。基本问题是如何将实体作为复合键的一部分包含在内,我在这里找到了答案:如何在JPA中创建包含@ManyToOne属性作为@EmbeddedId的复合主键?。设备:

@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;

设备型号:

@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;

诀窍是@MapsIdDeviceModel。这样就可以在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

以上是 如何在JPA中映射复合主键,其中主键的一部分是外键 的全部内容, 来源链接: utcz.com/qa/422640.html

回到顶部