我试图弄清楚如何构建JPA Entity bean以使数据适用于我的设备。这个数据库很老了,所以我无法改变架构。 Device Models具有复合主键,其中一列是FK到设备类型。
我尝试了几件不同的事情。首先是Device有一个DeviceModel和一个DeviceType,但这给了我一个错误,即太多的东西引用了dev_type。那么我试图让DeviceModel引用DeviceType,但我遇到了同样的错误。
如果它有帮助/重要,我使用Spring Data 4.2.x和Hibernate 4.3.8.Final支持所有内容。
我在网上找到的其他答案(例如How to create and handle composite primary key in JPA)对我没有帮助,因为它们只映射到基本数据类型。事实上,上面的答案是在我的代码中实现的......但我需要进一步提高1级。
架构:
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)
);
我的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
}
答案 0 :(得分:2)
嗯,你所遇到的基本问题是考虑列而不是实体,尽管这可能是一个不公平的陈述,因为这个问题有点棘手。基本问题是如何将实体作为复合键的一部分包含在内,我在这里找到答案:How to create a composite primary key which contains a @ManyToOne attribute as an @EmbeddedId in JPA?。 设备:
@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;
诀窍是@MapsId
中的DeviceModel
。这样就可以在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