Entity

Entity
你可以在EJB3规范所能提供的能力之外,就Hibernate对实体所作的一些操作进行优化。

@org.hibernate.annotations.Entity
追加了可能需要的额外的元数据,
而这些元数据超出了标准@Entity 中所定义的元数据。

mutable: 此实体是否为可变的

dynamicInsert: 用动态SQL新增

dynamicUpdate: 用动态SQL更新

selectBeforeUpdate: 指明Hibernate从不运行SQL UPDATE除非能确定对象的确已被修改

polymorphism: (指出)实体多态是PolymorphismType.IMPLICIT(默认)还是PolymorphismType.EXPLICIT

persister: allow the overriding of the default persister implementation

允许对默认持久实现(persister implementation)的覆盖

optimisticLock: 乐观锁策略(OptimisticLockType.VERSION, OptimisticLockType.NONE, OptimisticLockType.DIRTY 或 OptimisticLockType.ALL)

以下是一些附加的Hibernate注解扩展:

@org.hibernate.annotations.BatchSize 允许你定义批量抓取该实体的实例数量(如:@BatchSize(size=4))。
当加载一特定的实体时,Hibernate将加载在持久上下文中未经初始化的同类型实体,直至批量数量(上限)。

@org.hibernate.annotations.Proxy
定义了实体的延迟属性。Lazy(默认为true)定义了类是否为延迟(加载)。
proxyClassName是用来生成代理的接口(默认为该类本身)。

@org.hibernate.annotations.Where定义了当获取类实例时所用的SQL WHERE子句(该SQL WHERE子句为可选)。

@org.hibernate.annotations.Check
定义了在DDL语句中定义的合法性检查约束(该约束为可选)。

@OnDelete(action=OnDeleteAction.CASCADE)
定义于被连接(joined)的子类:在删除时使用SQL级连删除,而非通常的Hibernate删除机制。

@Table(name="tableName", indexes = {
@Index(name="index1", columnNames={"column1", "column2"} ) } )在tableName表的字段上创建定义好的索引。该注解可以被应用于关键表或者是其他次要的表。
@Tables 注解允许你在不同的表上应用索引。
此注解预期在使用
@javax.persistence.Table或
@javax.persistence.SecondaryTable的地方中出现.
@org.hibernate.annotations.Table 是对
@javax.persistence.Table的补充而不是它的替代品。

programlisting@Entity
@BatchSize(size=5)
@org.hibernate.annotations.Entity(
selectBeforeUpdate = true,
dynamicInsert = true, dynamicUpdate = true,
optimisticLock = OptimisticLockType.ALL,
polymorphism = PolymorphismType.EXPLICIT)
@Where(clause="1=1")
@org.hibernate.annotations.Table(name="Forest", indexes = { @Index(name="idx", columnNames = { "name", "length" } ) } )
public class Forest { ... }
programlisting@Entity
@Inheritance(
strategy=InheritanceType.JOINED
)
public class Vegetable { ... }

@Entity
@OnDelete(action=OnDeleteAction.CASCADE)
public class Carrot extends Vegetable { ... }

Identifier
@org.hibernate.annotations.GenericGenerator
允许你定义一个Hibernate特定的id生成器。

programlisting@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
public String getId() {

@Id @GeneratedValue(generator="hibseq")
@GenericGenerator(name="hibseq", strategy = "seqhilo",
parameters = {
@Parameter(name="max_lo", value = "5"),
@Parameter(name="sequence", value="heybabyhey")
}
)
public Integer getId() {

strategy is the short name of an Hibernate3
generator strategy or the fully qualified class name of an
IdentifierGenerator implementation. You can add
some parameters through the parameters
attribute

strategy可以是Hibernate3生成器策略的简称,或者是一个IdentifierGenerator实现的(带包路径的)全限定类名。
你可以通过parameters属性增加一些参数。

Property
Access type
访问类型是根据@Id或@EmbeddedId在实体继承层次中所处的位置推演而得的。子实体(Sub-entities),内嵌对象和被映射的父类均从根实体(root entity)继承访问类型。

在Hibernate中,你可以把访问类型覆盖成:


使用定制的访问类型策略

优化类级别或属性级别的访问类型

为支持这种行为,Hibernate引入了@AccessType注解。你可以对以下元素定义访问类型:

an entity

a superclass

an embeddable object

a property

实体

父类

可内嵌的对象

属性

被注解元素的访问类型会被覆盖,若覆盖是在类级别上,则所有的属性继承访问类型。
对于根实体,其访问类型会被认为是整个继承层次中的缺省设置(可在类或属性一级覆盖)。

若访问类型被标以"property",则Hibernate会扫描getter方法的注解,若访问类型被标以"field",则扫描字段的注解。否则,扫描标为@Id或@embeddedId的元素。

你可以覆盖某个属性(property)的访问类型,但是受注解的元素将不受影响:例如一个具有field访问类型的实体,(我们)可以将某个字段标注为 @AccessType("property"),则该字段的访问类型随之将成为property,但是其他字段上依然需要携带注解。

若父类或可内嵌的对象没有被注解,则使用根实体的访问类型(即使已经在非直系父类或可内嵌对象上定义了访问类型)。此时俄罗斯套娃(Russian doll)原理就不再适用。(译注:俄罗斯套娃(матрёшка或 матрешка)是俄罗斯特产木制玩具,一般由多个一样图案的空心木娃娃一个套一个组成,最多可达十多个,通常为圆柱形,底部平坦可以直立。)

programlisting@Entity
public class Person implements Serializable {
@Id @GeneratedValue //access type field
Integer id;

@Embedded
@AttributeOverrides({
@AttributeOverride(name = "iso2", column = @Column(name = "bornIso2")),
@AttributeOverride(name = "name", column = @Column(name = "bornCountryName"))
})
Country bornIn;
}

@Embeddable
@AccessType("property") //override access type for all properties in Country
public class Country implements Serializable {
private String iso2;
private String name;

public String getIso2() {
return iso2;
}

public void setIso2(String iso2) {
this.iso2 = iso2;
}

@Column(name = "countryName")
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

Formula


有时候,你想让数据库,而非JVM,来替你完成一些计算,也可能想创建某种虚拟字段(译注:即数据库视图)。你可以使用一段SQL(亦称为公式),而不是将属性映射到(物理)字段。 这种属性是只读的(属性值由公求得)。

programlisting@Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()

The SQL fragment can be as complex as you want avec even include
subselects.

SQL片段可以是任意复杂的,甚至可包含子查询。

Type
@org.hibernate.annotations.Type
覆盖了Hibernate所用的默认类型:这通常不是必须的,因为类型可以由Hibernate正确推得。
关于Hibernate类型的详细信息,请参考Hibernate使用手册。

@org.hibernate.annotations.TypeDef 和
@org.hibernate.annotations.TypeDefs允许你来声明类型定义。
这些注解被置于类或包一级。注意,对session factory来说,
这些定义将是全局的(即使定义于类一级),并且类型定义必须先于任何使用。

programlisting@TypeDefs(
{
@TypeDef(
name="caster",
typeClass = CasterStringType.class,
parameters = {
@Parameter(name="cast", value="lower")
}
)
}
)
package org.hibernate.test.annotations.entity;

...
public class Forest {
@Type(type="caster")
public String getSmallText() {
...
}

当使用组合的用户自定义类型时,你必须自己来表达字段定义。
@Columns就是为了此目的而引入的。

programlisting@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
@Columns(columns = {
@Column(name="r_amount"),
@Column(name="r_currency")
})
public MonetaryAmount getAmount() {
return amount;
}

public class MonetaryAmount implements Serializable {
private BigDecimal amount;
private Currency currency;
...
}

Index


通过在字段属性(property)上使用@Index注解,
可以在特定字段上定义索引,columnNames属性(attribute)将随之被忽略。

programlisting@Column(secondaryTable="Cat1")
@Index(name="story1index")
public String getStoryPart1() {
return storyPart1;
}

Inheritance


SINGLE_TABLE 是个功能强大的策略,但有时,特别对遗留系统而言,
是无法加入一个额外的识别符字段(discriminator column)。
由此,Hibernate引入了识别符公式(discriminator formula)的概念:
@DiscriminatorFormula是@DiscriminatorColumn的替代品,
它使用SQL片段作为识别符解决方案的公式( 不需要有一个专门的字段)。

programlisting@Entity
@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")
public class Forest { ... }

Association related annotations


默认情况下,当预期的被关联元素不在数据库中(关乎关联字段的id错误),致使Hiberante无法解决关联性问题时,Hibernate就会抛出异常。
这对遗留schema和历经拙劣维护的schema而言,这或有许多不便。
此时,你可用 @NotFound 注解让Hibernate略过这样的元素而不是抛出异常。
该注解可用于 @OneToOne (有外键)、 @ManyToOne 、
@OneToMany 或 @ManyToMany 关联。

programlisting@Entity
public class Child {
...
@ManyToOne
@NotFound(action=NotFoundAction.IGNORE)
public Parent getParent() { ... }
...
}

Collection related annotations
Parameter annotations


以下是可能的设置方式

用@BatchSizebatch设置集合的batch大小

用@Where注解设置Where子句

用注解@Check来设置check子句

用注解@OrderBy来设置SQL的order by子句

利用@OnDelete(action=OnDeleteAction.CASCADE) 注解设置级连删除策略

你也可以利用@Sort注解定义一个排序比较器(sort comparator),表明希望的比较器类型,无序、自然顺序或自定义排序,三者择一。若你想用你自己实现的comparator,
你还需要利用comparator属性(attribute)指明实现类。

programlisting@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
@Where(clause="1=1")
@OnDelete(action=OnDeleteAction.CASCADE)
public SortedSet<Ticket> getTickets() {
return tickets;
}

Please refer to the previous descriptions of these annotations
for more informations.

关于这些注解更详细的信息,请参阅此前的描述。

Extra collection types


比EJB3更胜一筹的是,Hibernate Annotations支持真正的List和Array。
映射集合的方式和以前完全一样,只不过要新增@IndexColumn注解。该注解允许你指明存放索引值的字段。你还可以定义代表数据库中首个元素的索引值(亦称为索引基数)。常见取值为0或1。

programlisting@OneToMany(cascade = CascadeType.ALL)
@IndexColumn(name = "drawer_position", base=1)
public List<Drawer> getDrawers() {
return drawers;
}

Hibernate Annotations还支持核心类型集合(Integer, String, Enums, ......)、
可内嵌对象的集合,甚至基本类型数组。这就是所谓的元素集合。

元素集合可用@CollectionOfElements来注解(作为@OneToMany的替代)。
为了定义集合表(译注:即存放集合元素的表,与下面提到的主表对应),要在关联属性上使用@JoinTable注解,joinColumns定义了介乎实体主表与集合表之间的连接字段(inverseJoincolumn是无效的且其值应为空)。
对于核心类型的集合或基本类型数组,你可以在关联属性上用@Column来覆盖存放元素值的字段的定义。你还可以用@AttributeOverride来覆盖存放可内嵌对象的字段的定义。

programlisting@Entity
public class Boy {
private Integer id;
private Set<String> nickNames = new HashSet<String>();
private int[] favoriteNumbers;
private Set<Toy> favoriteToys = new HashSet<Toy>();
private Set<Character> characters = new HashSet<Character>();

@Id @GeneratedValue
public Integer getId() {
return id;
}

@CollectionOfElements
public Set<String> getNickNames() {
return nickNames;
}

@CollectionOfElements
@JoinTable(
table=@Table(name="BoyFavoriteNumbers"),
joinColumns = @JoinColumn(name="BoyId")
)
@Column(name="favoriteNumber", nullable=false)
@IndexColumn(name="nbr_index")
public int[] getFavoriteNumbers() {
return favoriteNumbers;
}

@CollectionOfElements
@AttributeOverride( name="serial", column=@Column(name="serial_nbr") )
public Set<Toy> getFavoriteToys() {
return favoriteToys;
}

@CollectionOfElements
public Set<Character> getCharacters() {
return characters;
}
...
}

public enum Character {
GENTLE,
NORMAL,
AGGRESSIVE,
ATTENTIVE,
VIOLENT,
CRAFTY
}

@Embeddable
public class Toy {
public String name;
public String serial;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSerial() {
return serial;
}

public void setSerial(String serial) {
this.serial = serial;
}

public boolean equals(Object o) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;

final Toy toy = (Toy) o;

if ( !name.equals( toy.name ) ) return false;
if ( !serial.equals( toy.serial ) ) return false;

return true;
}

public int hashCode() {
int result;
result = name.hashCode();
result = 29 * result + serial.hashCode();
return result;
}
}

Cache
为了优化数据库访问,你可以激活所谓的Hibernate二级缓存。该缓存是可以按每个实体和集合进行配置的。

@org.hibernate.annotations.Cache定义了缓存策略及给定的二级缓存的范围。此注解适用于根实体(非子实体),还有集合。

programlisting@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }
programlisting@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
return tickets;
}
programlisting@Cache(
CacheConcurrencyStrategy usage();
String region() default "";
String include() default "all";
)

usage: the given cache concurrency strategy (NONE,
READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)

region (optional): the cache region (default to the fqcn of
the class or the fq role name of the collection)

include (optional): all to include all
properties, non-lazy to only include non lazy properties (default
all).

usage: 给定缓存的并发策略(NONE,
READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)

region (可选的):缓存范围(默认为类的全限定类名或是集合的全限定角色名)

include (可选的):值为all时包括了所有的属性(proterty),
为non-lazy时仅含非延迟属性(默认值为all)

Filters
Hibernate具有数据过滤器的概念,可在运行期应用于一个给定的session。过滤器需要事先定义好。

@org.hibernate.annotations.FilterDef 或
@FilterDefs 定义过滤器声明,为同名过滤器所用。
过滤器声明带有一个name()和一个parameters()数组,@ParamDef包含name和type,你还可以为给定的@filterDef定义一个defaultCondition()参数,当@Filter中没有任何定义时,可使用该参数定义缺省条件。
@FilterDef (s)可以在类或包一级进行定义。


现在我们来定义应用于实体或集合加载时的SQL过滤器子句。我们使用@Filter,并将其置于实体或集合元素上。

programlisting@Entity
@FilterDef(name="minLength", parameters={ @ParamDef( name="minLength", type="integer" ) } )
@Filters( {
@Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
@Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }

Queries
由于Hibernate引入了
@org.hibernate.annotations.NamedQuery,
@org.hibernate.annotations.NamedQueries,
@org.hibernate.annotations.NamedNativeQuery 和
@org.hibernate.annotations.NamedNativeQueries 命名式查询,因此Hibernate在命名式查询上比EBJ3规范中所定义的命名式查询提供了更多的特性。
他们在标准版中添加了可作为替代品的一些属性(attributes):


flushMode: 定义查询的刷新模式(Always, Auto, Commit或Never)

cacheable: 查询该不该被缓存

cacheRegion: 若查询已被缓存时所用缓存的范围

fetchSize: 针对该查询的JDBC statement单次获取记录的数目

timeout: 查询超时

callable: 仅用于本地化查询(native query),对于存储过程设为true

comment: 一旦激活注释功能,我们会在向数据库交送查询请求时看到注释

cacheMode: 缓存交护模式(get, ignore,normal,或refresh)

readOnly: 不管是否从查询获取元素都是在只读模式下

注意,EJB3已公开的最终草案中引入了@QueryHint的概念,
这可能是定义hints更好的方法。

猜你喜欢

转载自ssydxa219.iteye.com/blog/1616615