我在映射类的嵌入式属性时遇到麻烦。我创建了一些类,这些类与我试图说明的类相似。基本上,我有一个使用继承的@Embeddable类层次结构。顶级类“零件号”只有一个属性,扩展类没有为“零件号”类添加属性,它们仅添加了一些验证/逻辑。
这是我的意思:
部分
@Entity @Table(name="PART") public class Part { private Integer id; private String name; private PartNumber partNumber; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="PART_NAME") public String getName() { return name; } public void setName(String name) { this.name = name; } @Embedded public PartNumber getPartNumber() { return partNumber; } public void setPartNumber(PartNumber partNumber) { this.partNumber = partNumber; } }
零件号
@Embeddable public abstract class PartNumber { protected String partNumber; private String generalPartNumber; private String specificPartNumber; private PartNumber() { } public PartNumber(String partNumber) { this.partNumber = partNumber; } @Column(name = "PART_NUMBER") public String getPartNumber() { return partNumber; } public void setPartNumber(String partNumber) { this.partNumber = partNumber; } /** * @param partNumber * @return */ public boolean validate(String partNumber) { // do some validation return true; } /** * Returns the first half of the Part Number * * @return generalPartNumber */ @Transient public String getGeneralPartNumber() { return generalPartNumber; } /** * Returns the last half of the Part Number * which is specific to each Car Brand * * @return specificPartNumber */ @Transient public String getSpecificPartNumber() { return specificPartNumber; } }
福特PARTNUMBER
public class FordPartNumber extends PartNumber { /** * Ford Part Number is formatted as 1234-#1234 * * @param partNumber */ public FordPartNumber(String partNumber) { super(partNumber); validate(partNumber); } /* * (non-Javadoc) * * @see com.test.PartNumber#validate(java.lang.String) */ @Override public boolean validate(String partNumber) { // do some validation return true; } /* * (non-Javadoc) * * @see com.test.PartNumber#getGeneralPartNumber() */ @Override public String getGeneralPartNumber() { return partNumber; } /* * (non-Javadoc) * * @see com.test.PartNumber#getSpecificPartNumber() */ @Override public String getSpecificPartNumber() { return partNumber; } }
高贵的零件编号
public class ChevyPartNumber extends PartNumber { /** * Chevy Part Number is formatted as 1234-$1234 * * @param partNumber */ public ChevyPartNumber(String partNumber) { super(partNumber); validate(partNumber); } /* * (non-Javadoc) * * @see com.test.PartNumber#validate(java.lang.String) */ @Override public boolean validate(String partNumber) { // do some validation return true; } /* * (non-Javadoc) * * @see com.test.PartNumber#getGeneralPartNumber() */ @Override public String getGeneralPartNumber() { return partNumber; } /* * (non-Javadoc) * * @see com.test.PartNumber#getSpecificPartNumber() */ @Override public String getSpecificPartNumber() { return partNumber; } }
当然这是行不通的,因为Hibernate忽略了继承层次结构,并且不喜欢PartNumber是抽象的事实。 有什么方法可以使用JPA或Hibernate Annotations做到这一点? 我尝试使用@Inheritance JPA批注。
我无法重构层次结构的“ PartNumber”部分,因为原始开发人员希望能够使用N个XXXXPartNumber类扩展PartNumber。
有谁知道这样的事情是否会成为JPA 2.0或Hibernate的新版本的一部分?
不支持组件(例如@Embeddable)继承,并且很可能永远不会支持。这样做有充分的理由- 实体标识符在Hibernate支持的所有继承策略中都起着至关重要的作用,而组件没有(映射)标识符。
您有三种选择:
A)将零件编号(及其所有后代)映射为实体。PartNumber可能保持抽象:
@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="part_type", discriminatorType=DiscriminatorType.STRING) public abstract class PartNumber { ... } @Entity @DiscriminatorValue("Ford") public class FordPartNumber extends PartNumber { ... }
B)根据您的示例,似乎所有PartNumber后代的行为仅有所不同(它们没有引入要存储的任何新属性)。如果确实如此,您可以将PartNumber属性加上您自己的鉴别符值(这样就知道要实例化哪个类)作为@Embedded私有属性,并在部件类中将get / setPartNumber()访问器编组/取消编组适当的子类。您甚至可以编写自己的Hibernate自定义类型来为您完成此操作(这非常简单)。
C)如果PartNumber后代确实在必须存储的属性方面有所不同,并且由于任何原因将它们映射为实体都是不可接受的,则可以使用marshall/unmarshall将它们字符串化(作为XML或其他适合帐单的字符串)并将其存储。我将XStream用于此确切目的,并且编写了一个简单的Hibernate类型来配合它。您的零件映射看起来像
@Type(type="xmlBean") public PartNumber getPartNumber() { return partNumber; } public void setPartNumber(PartNumber partNumber) { this.partNumber = partNumber; }
并且PartNumber后代完全不需要映射。当然,缺点是,在数据库中处理XML有点麻烦,因此对于可能需要报告的内容而言,这可能不是理想的方法。OTOH,我使用它来存储插件设置,这为我节省 了 映射/数据库维护 的许多 麻烦。