Java 如何使用JPA和Hibernate映射复合密钥?
在这段代码中,如何为组合键生成Java类(如何在hibernate中组合键): 您需要使用:Java 如何使用JPA和Hibernate映射复合密钥?,java,hibernate,jpa,orm,composite-key,Java,Hibernate,Jpa,Orm,Composite Key,在这段代码中,如何为组合键生成Java类(如何在hibernate中组合键): 您需要使用: 看起来你是白手起家的。尝试使用可用的反向工程工具,如数据库中的Netbeans实体,以至少实现基本的自动化(如嵌入式ID)。如果你有很多桌子,这可能会成为一个巨大的头痛。我建议避免重新发明轮子,使用尽可能多的可用工具将编码减少到最低和最重要的部分,即您想要做的事情。要映射复合键,您可以使用EmbeddedId或IdClass注释。我知道这个问题并不是关于JPA的,但是规范中定义的规则也适用。因此,它们是
看起来你是白手起家的。尝试使用可用的反向工程工具,如数据库中的Netbeans实体,以至少实现基本的自动化(如嵌入式ID)。如果你有很多桌子,这可能会成为一个巨大的头痛。我建议避免重新发明轮子,使用尽可能多的可用工具将编码减少到最低和最重要的部分,即您想要做的事情。要映射复合键,您可以使用
EmbeddedId
或IdClass
注释。我知道这个问题并不是关于JPA的,但是规范中定义的规则也适用。因此,它们是:
2.1.4主键和实体标识
复合主键必须是
对应于单个
永久性字段或属性,或指向
一组字段或属性,如
如下所述。主键类
必须定义以表示
复合主键。混合成的
主键通常出现在
当
数据库密钥由几个
列嵌入ID的和
IdClass
注释用于
表示复合主键。
请参阅
第9.1.14节和第9.1.15节
以下规则适用于
复合主键:
- 主键类必须是public,并且必须具有public no arg 构造函数。
- 如果使用基于属性的访问,则主键的属性 类必须是公共的或受保护的
- 主键类必须是可序列化的
- 主键类
必须定义
值的语义 必须确保这些方法的平等性 与数据库一致 对于要将 键已映射等于
和
方法。hashCode
- 复合主键必须表示为 可嵌入类(见第9.1.14节, “EmbeddedId注释”)或必须为 表示并映射到多个 实体的字段或属性 等级(见第9.1.15节“IdClass 注释”)
- 如果复合主键类映射到多个字段或 实体类的属性 主键字段的名称或 主键类中的属性 而实体类的那些必须 对应,其类型必须为 一样
IdClass
复合主键的类可以如下所示(可以是静态内部类):
以及该实体:
@Entity
@IdClass(TimePK.class)
class Time implements Serializable {
@Id
private Integer levelStation;
@Id
private Integer confPathID;
private String src;
private String dst;
private Integer distance;
private Integer price;
// getters, setters
}
@Entity
class Time implements Serializable {
@EmbeddedId
private TimePK timePK;
private String src;
private String dst;
private Integer distance;
private Integer price;
//...
}
IdClass
注释将多个字段映射到表PK
带有EmbeddedId
复合主键的类可以如下所示(可以是静态内部类):
以及该实体:
@Entity
@IdClass(TimePK.class)
class Time implements Serializable {
@Id
private Integer levelStation;
@Id
private Integer confPathID;
private String src;
private String dst;
private Integer distance;
private Integer price;
// getters, setters
}
@Entity
class Time implements Serializable {
@EmbeddedId
private TimePK timePK;
private String src;
private String dst;
private Integer distance;
private Integer price;
//...
}
@EmbeddedId
注释将PK类映射到表PK
差异:
- 从物理模型的角度来看,没有区别
以某种方式更清楚地传达了一个信息,即密钥是一个复合密钥,当组合的pk本身是一个有意义的实体或在代码中重用时,IMO是有意义的@EmbeddedId
用于指定某些字段组合是唯一的,但这些字段没有特殊含义@IdClass
- 使用
IdClass
select t.levelStation from Time t
- 带有
EmbeddedId
select t.timePK.levelStation from Time t
- JPA1.0规范
- 第2.1.4节“主键和实体标识”
- 第9.1.14节“嵌入式ID注释”
- 第9.1.15节“IdClass注释”
公共类路径{
私有映射timeForLevelStation=newhashmap();
公共时间getTime(长时间站){
返回timeForLevelStation.get(levelStation);
}
public void putTime(long levelStation,Time newValue){
timeForLevelStation.put(levelStation,newValue);
}
}
公共课时间{
字符串src;
字符串dst;
长途;
多头价格;
公共长途电话(){
返回距离;
}
公共距离(长距离){
这个距离=距离;
}
公共字符串getDst(){
返回dst;
}
公共无效设置dst(字符串dst){
this.dst=dst;
}
公共长期价格(){
退货价格;
}
公共定价(长期价格){
这个价格=价格;
}
公共字符串getSrc(){
返回src;
}
公共void setSrc(字符串src){
this.src=src;
}
}
映射:
<class name="ConfPath" table="ConfPath">
<id column="ID" name="id">
<generator class="native"/>
</id>
<map cascade="all-delete-orphan" name="values" table="example"
lazy="extra">
<key column="ConfPathID"/>
<map-key type="long" column="levelStation"/>
<composite-element class="Time">
<property name="src" column="src" type="string" length="100"/>
<property name="dst" column="dst" type="string" length="100"/>
<property name="distance" column="distance"/>
<property name="price" column="price"/>
</composite-element>
</map>
</class>
主键类必须定义equals和hashCode方法
更严格地说:您应该遵循Liskows替换原则,忽略对称性李>
让我们举一个简单的例子。假设有两个表名
select t.timePK.levelStation from Time t
public class ConfPath {
private Map<Long,Time> timeForLevelStation = new HashMap<Long,Time>();
public Time getTime(long levelStation) {
return timeForLevelStation.get(levelStation);
}
public void putTime(long levelStation, Time newValue) {
timeForLevelStation.put(levelStation, newValue);
}
}
public class Time {
String src;
String dst;
long distance;
long price;
public long getDistance() {
return distance;
}
public void setDistance(long distance) {
this.distance = distance;
}
public String getDst() {
return dst;
}
public void setDst(String dst) {
this.dst = dst;
}
public long getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
}
<class name="ConfPath" table="ConfPath">
<id column="ID" name="id">
<generator class="native"/>
</id>
<map cascade="all-delete-orphan" name="values" table="example"
lazy="extra">
<key column="ConfPathID"/>
<map-key type="long" column="levelStation"/>
<composite-element class="Time">
<property name="src" column="src" type="string" length="100"/>
<property name="dst" column="dst" type="string" length="100"/>
<property name="distance" column="distance"/>
<property name="price" column="price"/>
</composite-element>
</map>
</class>
<composite-id>
<!--<key-many-to-one name="productId" class="databaselayer.users.UserDB" column="user_name"/>-->
<key-property name="productId" column="PRODUCT_Product_ID" type="int"/>
<key-property name="categoryId" column="categories_id" type="int" />
</composite-id>
public class PK implements Serializable{
private int PRODUCT_Product_ID ;
private int categories_id ;
public PK(int productId, int categoryId) {
this.PRODUCT_Product_ID = productId;
this.categories_id = categoryId;
}
public int getPRODUCT_Product_ID() {
return PRODUCT_Product_ID;
}
public void setPRODUCT_Product_ID(int PRODUCT_Product_ID) {
this.PRODUCT_Product_ID = PRODUCT_Product_ID;
}
public int getCategories_id() {
return categories_id;
}
public void setCategories_id(int categories_id) {
this.categories_id = categories_id;
}
private PK() { }
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals(PRODUCT_Product_ID, pk.PRODUCT_Product_ID ) &&
Objects.equals(categories_id, pk.categories_id );
}
@Override
public int hashCode() {
return Objects.hash(PRODUCT_Product_ID, categories_id );
}
}
@Entity(name = "product_category")
@IdClass( PK.class )
public class ProductCategory implements Serializable {
@Id
private int PRODUCT_Product_ID ;
@Id
private int categories_id ;
public ProductCategory(int productId, int categoryId) {
this.PRODUCT_Product_ID = productId ;
this.categories_id = categoryId;
}
public ProductCategory() { }
public int getPRODUCT_Product_ID() {
return PRODUCT_Product_ID;
}
public void setPRODUCT_Product_ID(int PRODUCT_Product_ID) {
this.PRODUCT_Product_ID = PRODUCT_Product_ID;
}
public int getCategories_id() {
return categories_id;
}
public void setCategories_id(int categories_id) {
this.categories_id = categories_id;
}
public void setId(PK id) {
this.PRODUCT_Product_ID = id.getPRODUCT_Product_ID();
this.categories_id = id.getCategories_id();
}
public PK getId() {
return new PK(
PRODUCT_Product_ID,
categories_id
);
}
}
@Embeddable
public class EmployeeId implements Serializable {
@Column(name = "company_id")
private Long companyId;
@Column(name = "employee_number")
private Long employeeNumber;
public EmployeeId() {
}
public EmployeeId(Long companyId, Long employeeId) {
this.companyId = companyId;
this.employeeNumber = employeeId;
}
public Long getCompanyId() {
return companyId;
}
public Long getEmployeeNumber() {
return employeeNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EmployeeId)) return false;
EmployeeId that = (EmployeeId) o;
return Objects.equals(getCompanyId(), that.getCompanyId()) &&
Objects.equals(getEmployeeNumber(), that.getEmployeeNumber());
}
@Override
public int hashCode() {
return Objects.hash(getCompanyId(), getEmployeeNumber());
}
}
@Entity(name = "Employee")
@Table(name = "employee")
public class Employee {
@EmbeddedId
private EmployeeId id;
private String name;
public EmployeeId getId() {
return id;
}
public void setId(EmployeeId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity(name = "Phone")
@Table(name = "phone")
public class Phone {
@Id
@Column(name = "`number`")
private String number;
@ManyToOne
@JoinColumns({
@JoinColumn(
name = "company_id",
referencedColumnName = "company_id"),
@JoinColumn(
name = "employee_number",
referencedColumnName = "employee_number")
})
private Employee employee;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}