Hibernate——映射基础

 

映射的规则:所有的双向关联都需要有一端被设置为reverse,在一对多的关联中,它必须是代表多的那端,在多对多的关联中,它可以任意选取一端,因为两端之间没有差别。

 

1、Entity

@Entity

public class Flight implements Serializable {     Long id;     @Id     public Long getId() { return id; }     public void setId(Long id) { this.id = id; }

}
  实体是一个被hibernate 持久化的java 对象。
  
@Entity

@Table(name="TBL_FLIGHT",         schema="AIR_COMMAND",         uniqueConstraints=            @UniqueConstraint(                name="flight_number",                 columnNames={"comp_prefix", "flight_number"} ) )
  @Table是类一级的映射。可以为实体映射指定表(table),目录(catalog)和schema。结合@UniqueConstraint可以指定表的唯一约束。
 
2、Identifiers
 
<id

        name="propertyName"

        type="typename"

        column="column_name"

        unsaved-value="null|any|none|undefined|id_value"

        access="field|property|ClassName">

        node="element-name|@attribute-name|element/@attribute|."



        <generator class="generatorClass"/>

</id>
 
 大家一定要扭转一个观点,在Hibernate中,主键属性定义为基本类型,并不能够比定义为对象型效率来的高,而且也多了很多麻烦,因此建议大家使用对象型的Integer/Long定义主键。
 
  2.1、组合标识符
  
  2.1.1 id作为一个组件类型的属性
@Entity

class User {    @EmbeddedId    @AttributeOverride(name="firstName", column=@Column(name="fld_firstname")    UserId id;    Integer age;

}



@Embeddable

class UserId implements Serializable {    String firstName;    String lastName;
   public UserId(){};
   //implements equals and hashcode…
}
  
 

主键类必需满足下列条件:
(1)必需被序列化
(2)必需有一个公共的无参构造方法
(3)必需实现equals()和hashCode()方法

 

对应的xml配置为:
<class name="User">    <composite-id name="id" class="UserId">       <key-property name="firstName" column="fld_firstname"/>       <key-property name="lastName"/>    </composite-id>

</class>
 
 2.2 主键生成器
  hibernate提供多种主键生成策略,首先先看几种JPA支持的策略:
  1)IDENTITY:supports identity columns in DB2, MySQL, MS SQL Server, Sybase and HypersonicSQL。返回的标识符是long,short和int类型。
  2)SEQUENCE:需要数据库支持sequence。返回的标识符是long,short和int类型。
  3)TABLE:需要特定的数据库支持。返回的标识符是long,short和int类型。
  4)AUTO:根据数据库自动选择.如果没有指定,默认是该策略。
@Entity

public class Customer {    @Id @GeneratedValue    Integer getId() { ... };

}



@Entity  public class Invoice {    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)    Integer getId() { ... };

}
SEQUENCETABLE需要额外的配置,例如:
 
@Id  @GeneratedValue(     strategy=GenerationType.SEQUENCE,      generator="SEQ_GEN")

@javax.persistence.SequenceGenerator(     name="SEQ_GEN",     sequenceName="my_sequence",     allocationSize=20

)

public Integer getId() { ... } 
@Id @GeneratedValue( strategy=GenerationType.TABLE, generator="TABLE_GEN") 
@javax.persistence.TableGenerator(     name="TABLE_GEN",     table="GENERATOR_TABLE",     pkColumnName = "key",     valueColumnName = "hi"     pkColumnValue="EMP",     allocationSize=20

)

 
 2.3 加强型主键生成器:
  1)org.hibernate.id.enhanced.SequenceStyleGenerator
  2)org.hibernate.id.enhanced.TableGenerator
  加强型主键生成器的优化,不用每次请求都查询数据库。
3、主动锁属性
  当使用长事务时,加入版本属性,非常有用。可以保证如果一个实体被两个会话更新,后面一个更新不会覆盖前面的更新。
@Entity

public class Flight implements Serializable {

...     @Version     @Column(name="OPTLOCK")     public Integer getVersion() { ... }

}  
@Entity

public class Flight implements Serializable {

...     @Version     public Date getLastUpdate() { ... }

}  
 4、Property
  
  如果一个property,不是static类型,也没有标注@Transient,那么默认被认为是要持久化的。
 
   4.1
  Property注解中用到的比较多的几个是:@Transient,@Basic,@Temporal,@Lob
  例子:
public transient int counter; //transient property



private String firstname; //persistent property



@Transient

String getLengthInMeter() { ... } //transient property



String getName() {... } // persistent property



@Basic

int getLength() { ... } // persistent property



@Basic(fetch = FetchType.LAZY)

String getDetailedComment() { ... } // persistent property



@Temporal(TemporalType.TIME)

java.util.Date getDepartureTime() { ... } // persistent property            @Enumerated(EnumType.STRING)  //Hibernate创造性的支持enum类型,数据库中的字段是序数或者字符串

Starred getNote() { ... } //enum persisted as String in database
 
@Lob

public String getFullText() {     return fullText;

}



@Lob

public byte[] getFullCode() {     return fullCode;

}
  
@Column(

    name="columnName";

    boolean unique() default false;

    boolean nullable() default true;

    boolean insertable() default true;

    boolean updatable() default true;

    String columnDefinition() default "";

    String table() default "";

    int length() default 255;

    int precision() default 0; // decimal precision

    int scale() default 0; // decimal scal
    )
  4.2
@Formula
  需要在数据库中进行一些运算,可以通过@Formula创建一些虚字段,这类属性是只读的。
@Formula("obj_length * obj_height * obj_width")

public long getObjectVolume()
  4.3
@Embedded objects(也叫做Component)
  Embeddable对象是它的属性映射到与嵌入它的类同一个表中。
  可以在实体中定义一个嵌入式组件,甚至可以覆盖该实体原有的列映射。
  组件类必须在类一级通过@Embeddable注解声明。在特定的实体中,通过@Embedded和@AttributeOverride注解可以覆盖该实体原有的列映射。
@Entity

public class Person implements Serializable {     // Persistent component using defaults     Address homeAddress;     @Embedded     @AttributeOverrides( {             @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),             @AttributeOverride(name="name", column = @Column(name="bornCountryName") )     } )     Country bornIn;     ...

}   
    
@Embeddable

public class Address implements Serializable {     String city;     Country nationality; //no overriding here

} 
 
@Embeddable

public class Country implements Serializable {     private String iso2;     @Column(name="countryName") private String name;     public String getIso2() { return iso2; }     public void setIso2(String iso2) { this.iso2 = iso2; }          public String getName() { return name; }     public void setName(String name) { this.name = name; }     ...

}            
  嵌入式组件的访问类型(Access Type)与它的属主实体一致,当然也可以通过@Access注解来改变它。
  
  在Person实体中,虽然homeAddress没有标注@Embedded,但是hibernate会自动检测其对应的Address类的@Embeddable注解,并将其作为一个持久化属性。
  
  4.4 继承策略
  
  Java支持多态,所以持久化类有以下几种继承策略:
  1)SINGLE_TABLE策略:所有的类,包括其继承类的实例全部对应到一张表中
  2)JOINED策略:父类和子类对应不同的表,子类对应的表中只存在其扩展的特殊的属性(不包含从父类继承过来的属性)
  3)TABLE_PER_CLASS策略:父类和子类都对应不同的表,子类对应的表中存在所有的属性(包含
从父类继承下来的所有属性)
  
  4.4.1 SINGLE_TABLE策略:
  每个子类都可以有自己的实体化属性及子类。Version和id属性在根类中声明。继承结构中每个子类都必须定义个唯一的discriminator value,如果没有声明,默认为java类的全限定名。
  @Inheritance和@DiscrimininatorColumn在根类中声明。
 
@Entity

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(     name="planetype",     discriminatorType=DiscriminatorType.STRING

)

@DiscriminatorValue("Plane")

public class Plane { ... }



@Entity

@DiscriminatorValue("A320")

public class A320 extends Plane { ... }   
  对应xml配置文件中:
<subclass

        name="ClassName"

        discriminator-value="discriminator_value"

        proxy="ProxyInterface"

        lazy="true|false"

        dynamic-update="true|false"

        dynamic-insert="true|false"

        entity-name="EntityName"

        node="element-name"

        extends="SuperclassName">



        <property .... />

        .....

</subclass>

  4.4.2 JOINED策略:

 

   每个子类都可以映射到自己的表。该映射策略需要一个discriminator column,每个子类都要声明一个column来保存对象标识符。这个表通过@PrimaryKeyJoinColumns 或者<key>元素指定的主键同时也是指向父类表的外键。

@Entity @Table(name="CATS")

@Inheritance(strategy=InheritanceType.JOINED)

public class Cat implements Serializable {      @Id @GeneratedValue(generator="cat-uuid")      @GenericGenerator(name="cat-uuid", strategy="uuid")     String getId() { return id; }     ...

}



@Entity @Table(name="DOMESTIC_CATS")

@PrimaryKeyJoinColumn(name="CAT")

public class DomesticCat extends Cat {      public String getName() { return name; }

}  
 
  对应xml配置文件:
<joined-subclass

        name="ClassName"

        table="tablename"

        proxy="ProxyInterface"

        lazy="true|false"

        dynamic-update="true|false"

        dynamic-insert="true|false"

        schema="schema"

        catalog="catalog"

        extends="SuperclassName"

        persister="ClassName"

        subselect="SQL expression"

        entity-name="EntityName"

        node="element-name">



        <key .... >



        <property .... />

        .....

</joined-subclass>

 

  4.4.3 将一个实体映射到多个表

   在新的应用中,不推荐这么做。

 

  5、@OneToOne关联

    one to one关联有三种方式:

    1)关联实体享有同样的主键

    2)其中一个实体通过外键关联到另外一个实体的主键

    3)通过关联表来保存两个实体间的关联

   相应这三种方式的设置:

    1)关联实体享有同样的主键,这种方式个人感觉并不是很好的设计,耦合性太强

@Entity

public class Flight implements Serializable {     @OneToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )     @PrimaryKeyJoinColumn     public Company getCompany() {         return company;     }     ...

}  

 

   2)通过主外键关联:

@Entity

public class Flight implements Serializable {     @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )     @JoinColumn(name="COMP_ID")     public Company getCompany() {         return company;     }     ...

}



public interface Company {     ...

}
  
  3)通过关联表关联:
@Entity

public class Flight implements Serializable {

    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )     @JoinTable(name="Flight_Company",         joinColumns = @JoinColumn(name="FLIGHT_ID"),         inverseJoinColumns = @JoinColumn(name="COMP_ID")     )     public Company getCompany() {         return company;     }     ...

} 

你可能感兴趣的:(Hibernate)