我想知道hibernate是否对特定类型的类强加任何限制以保持它们。我已经读过Hibernate可以持久化JavaBean类和Pojos。
这是否意味着hibernate不能持久化不属于这两类的类?
我们可以在hibernate中持久化非pojo类吗?例如
Class A extends B{}
基本上我需要知道是什么让hibernate无法在RDBMS中持久化一个类?
答案 0 :(得分:3)
持久类是应用程序中实现业务问题实体的类(例如,电子商务应用程序中的客户和订单)。并非所有持久化类的实例都被认为处于持久状态。例如,实例可以是瞬态的或分离的。
如果这些类遵循一些简单的规则(也称为Plain Old Java Object(POJO)编程模型),则Hibernate的效果最佳。但是,这些规则都不是硬性要求。实际上,Hibernate3对持久对象的性质几乎没有假设。您可以通过其他方式表达域模型(例如,使用Map实例树)。
大多数Java应用程序都需要一个代表felines的持久化类。例如:
public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
private Set kittens = new HashSet();
private void setId(Long id) {
this.id=id;
}
public Long getId() {
return id;
}
void setBirthdate(Date date) {
birthdate = date;
}
public Date getBirthdate() {
return birthdate;
}
void setWeight(float weight) {
this.weight = weight;
}
public float getWeight() {
return weight;
}
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
void setSex(char sex) {
this.sex=sex;
}
public char getSex() {
return sex;
}
void setLitterId(int id) {
this.litterId = id;
}
public int getLitterId() {
return litterId;
}
void setMother(Cat mother) {
this.mother = mother;
}
public Cat getMother() {
return mother;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
public Set getKittens() {
return kittens;
}
// addKitten not needed by Hibernate
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}
持久类的四个主要规则: 1.实现无参数构造函数
Cat有一个无参数的构造函数。所有持久化类必须具有默认构造函数(可以是非公共的),以便Hibernate可以使用Constructor.newInstance()实例化它们。建议您使用默认构造函数,至少在Hibernate中生成运行时代理的包可见性。 2.2。提供标识符属性(可选)
Cat有一个名为id的属性。此属性映射到数据库表的主键列。该属性可能被称为任何东西,它的类型可能是任何原始类型,任何原始"包装" type,java.lang.String或java.util.Date。如果旧数据库表具有复合键,则可以使用具有这些类型属性的用户定义类(请参阅本章后面的复合标识符部分。)
identifier属性是严格可选的。您可以将它们关闭,让Hibernate在内部跟踪对象标识符。但是,我们不建议这样做。
实际上,某些功能仅适用于声明标识符属性的类:
分离对象的传递重新附加(级联更新或级联合并) - 请参见第10.11节“传递持久性” Session.saveOrUpdate() Session.merge()的 我们建议您在持久化类上声明一致命名的标识符属性,并使用可空(即非原始)类型。
Hibernate的一个核心功能是代理,它依赖于持久化的类是非final的,或者是声明所有公共方法的接口的实现。
您可以保留未实现Hibernate接口的最终类。但是,您不能使用代理进行延迟关联提取,这最终会限制性能调整的选项。
您还应该避免在非最终类上声明公共最终方法。如果要使用具有公共最终方法的类,则必须通过设置lazy =" false"来明确禁用代理。
Cat为其所有持久字段声明了访问器方法。许多其他ORM工具直接持久化实例变量。最好在关系模式和类的内部数据结构之间提供间接。默认情况下,Hibernate持久化JavaBeans样式属性并识别形式为getFoo,isFoo和setFoo的方法名称。如果需要,您可以切换到特定属性的直接字段访问。
不需要将属性声明为公共 - Hibernate可以使用默认的,受保护的或私有的get / set对来保留属性。
实施继承
子类还必须遵守第一和第二规则。它从超类Cat继承了它的标识符属性。例如:
包裹例如;
public class DomesticCat extends Cat {
private String name;
public String getName() {
return name;
}
protected void setName(String name) {
this.name=name;
}
}
实现equals()和hashCode()
如果您:
,则必须覆盖equals()和hashCode()方法打算将持久化类的实例放在一个Set中(推荐的表示多值关联的方式);和 打算使用重新附加的分离实例 Hibernate仅在特定会话范围内保证持久标识(数据库行)和Java标识的等效性。混合在不同会话中检索的实例时,如果希望对集合具有有意义的语义,则必须实现equals()和hashCode()。
最明显的方法是通过比较两个对象的标识符值来实现equals()/ hashCode()。如果值相同,则两者必须是相同的数据库行,因为它们是相等的。如果两者都添加到Set中,则Set中只有一个元素。遗憾的是,您无法将该方法与生成的标识符一起使用。 Hibernate只会将标识符值分配给持久化的对象;新创建的实例将没有任何标识符值。此外,如果实例未保存且当前位于Set中,则保存它将为对象分配标识符值。如果equals()和hashCode()基于标识符值,则哈希码将更改,从而破坏Set的约定。有关此问题的完整讨论,请参阅Hibernate网站。这不是Hibernate问题,而是对象标识和相等的正常Java语义。
建议您使用Business key equality实现equals()和hashCode()。业务键等式意味着equals()方法仅比较形成业务键的属性。它是识别我们在现实世界中的实例的关键(一个自然的候选键):
公共类Cat {
...
public boolean equals(Object other) {
if (this == other) return true;
if ( !(other instanceof Cat) ) return false;
final Cat cat = (Cat) other;
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
if ( !cat.getMother().equals( getMother() ) ) return false;
return true;
}
public int hashCode() {
int result;
result = getMother().hashCode();
result = 29 * result + getLitterId();
return result;
}
} 业务密钥不必像数据库主键候选一样可靠。不可变或唯一属性通常是业务密钥的良好候选。
答案 1 :(得分:0)
从实践中我知道对象持久性的这种限制:
在现实世界中,pojo和java bean并不是你需要的所有东西,也不需要成功的工作。