EJB3.0-JPA实体的注解规范以及Hibernate特有的扩展

来源:互联网 发布:mac按键精灵使用教程 编辑:程序博客网 时间:2024/06/02 06:39

EJB3.0-JPA实体的注解规范以及Hibernate特有的扩展(2)

原文地址:http://hi.baidu.com/fengfan_2008/blog/item/34a9fd25d22b0f20d5074264.html

 

一对一关联可能是双向的.在双向关联中,有且仅有一端是作为主体(owner)端存在的:主体端负责维护联接列(即更新).
对于不需要维护这种关系的从表则通过mappedBy属性进行声明.
mappedBy的值指向主体的关联属性.
在上面这个例子中,mappedBy的值为 passport.
最后,不必也不能再在被关联端(owned side)定义联接列了,因为已经在主体端进行了声明.

如果在主体没有声明@JoinColumn,系统自动进行处理:
在主表(owner table)中将创建联接列,
列名为:主体的关联属性名+下划线+被关联端的主键列名.
在上面这个例子中是passport_id,
因为Customer中关联属性名为passport,
Passport的主键是id.
        The third possibility (using an association table) is very
        exotic.
        第三种方式也许是最另类的(通过关联表).
       
@Entity
public class Customer implements Serializable {
    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(name = "CustomerPassports"
        joinColumns = @JoinColumn(name="customer_fk"),
        inverseJoinColumns = @JoinColumns(name="passport_fk")
    )
    public Passport getPassport() {
        ...
    }

@Entity
public class Passport implements Serializable {
    @OneToOne(mappedBy = "passport")
    public Customer getOwner() {
    ...
}
           

    Customer通过名为 CustomerPassports的关联表和Passport关联; 该关联表拥有名为passport_fk的外键列,该外键指向Passport表,该信息定义为inverseJoinColumn的属性值,而customer_fk外键列指向Customer表,该信息定义为 joinColumns的属性值.
你必须明确定义关联表名和关联列名.
在实体属性一级使用@ManyToOne注解来定义多对一关联:    
@Entity()
public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
    @JoinColumn(name="COMP_ID")
    public Company getCompany() {
        return company;
    }
    ...
}
   其中@JoinColumn是可选的,关联字段默认值和一对一(one to one)关联的情况相似,
列名为:主体的关联属性名+下划线+被关联端的主键列名.
在这个例子中是company_id,因为关联的属性是company,Company的主键是id.

@ManyToOne注解有一个名为targetEntity的参数,
该参数定义了目标实体名.通常不需要定义该参数,
因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了.
不过下面这种情况下这个参数就显得有意义了:使用接口作为返回值而不是常见的实体.
  
@Entity()
public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE},             role="bold">targetEntity=CompanyImpl.class )
    @JoinColumn(name="COMP_ID")
    public Company getCompany() {
        return company;
    }
    ...
}

public interface Company {
    ...
           
对于多对一也可以通过关联表的方式来映射.
通过@JoinTable注解可定义关联表,该关联表包含了指回实体表的外键(通过@JoinTable.joinColumns)
以及指向目标实体表的外键(通过@JoinTable.inverseJoinColumns).

@Entity()
public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
    @JoinTable(name="Flight_Company",
        joinColumns = @JoinColumn(name="FLIGHT_ID"),
        inverseJoinColumns = @JoinColumns(name="COMP_ID")
    )
    public Company getCompany() {
        return company;
    }
    ...
}
           
    你可以对 Collection ,List(指有序列表, 而不是索引列表),Map和Set这几种类型进行映射.
    EJB3规范定义了怎么样使用@javax.persistence.OrderBy
    注解来对有序列表进行映射:
    该注解接受的参数格式:用逗号隔开的(目标实体)属性名及排序指令,如firstname asc, age desc,如果该参数为空,则默认以id对该集合进行排序.
    如果某个集合在数据库中对应一个关联表(association table)的话,你不能在这个集合属性上面使用@OrderBy注解.
    对于这种情况的处理方法,请参考.
    EJB3 允许你利用目标实体的一个属性作为Map的key,
    这个属性可以用@MapKey(name="myProperty")来声明.
    如果使用@MapKey注解的时候不提供属性名,
    系统默认使用目标实体的主键.
    map的key使用和属性相同的列:不需要为map key定义专用的列,因为map key实际上就表达了一个目标属性.
    注意一旦加载,key不再和属性保持同步,也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新
    (请参考).
    很多人被<map>和@MapKey弄糊涂了.
    其他它们有两点区别.@MapKey目前还有一些限制,详情请查看论坛或者我们的JIRA缺陷系统.
    注意一旦加载,key不再和属性保持同步,也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新.
    (Hibernate 3中Map支持的方式在当前的发布版中还未得到支持).          Hibernate将集合分以下几类.
    语义
     Java实现类
     注解
               
     Bag 语义
java.util.List, java.util.Collection
@org.hibernate.annotations.CollectionOfElements 或
@OneToMany 或 @ManyToMany
               
带主键的Bag语义(没有普通Bag语义的限制)
java.util.List, java.util.Collection
(@org.hibernate.annotations.CollectionOfElements 或
@OneToMany 或 @ManyToMany) 和 @CollectionId
               
List 语义
java.util.List
(@org.hibernate.annotations.CollectionOfElements 或@OneToMany 或 @ManyToMany)
以及 @org.hibernate.annotations.IndexColumn

Set 语义
java.util.Set
@org.hibernate.annotations.CollectionOfElements 或
@OneToMany 或 @ManyToMany
               
Map 语义
java.util.Map
(@org.hibernate.annotations.CollectionOfElements 或@OneToMany 或 @ManyToMany)
以及(空或@org.hibernate.annotations.MapKey/MapKeyManyToMany(支持真正的map), 或@javax.persistence.MapKey

从上面可以明确地看到,没有@org.hibernate.annotations.IndexColumn
注解的java.util.List集合将被看作bag类.
   
EJB3规范不支持原始类型,核心类型,嵌入式对象的集合.但是Hibernate对此提供了支持
    (详情参考 ).

    @Entity public class City {
    @OneToMany(mappedBy="city")
    @OrderBy("streetName")
    public List<Street> getStreets() {
        return streets;
    }
...
}

@Entity public class Street {
    public String getStreetName() {
        return streetName;
    }

    @ManyToOne
    public City getCity() {
        return city;
    }
    ...
}

@Entity
public class Software {
    @OneToMany(mappedBy="software")
    @MapKey(name="codeName")
    public Map<String, Version> getVersions() {
        return versions;
    }
...
}

@Entity
@Table(name="tbl_version")
public class Version {
    public String getCodeName() {...}

    @ManyToOne
    public Software getSoftware() { ... }
...
}
上面这个例子中,City中包括了以streetName排序的Street的集合.而Software中包括了以codeName作为key和以Version作为值的Map.

除非集合为generic类型,否则你需要指定targetEntity.
这个注解属性接受的参数为目标实体的class.
在属性级使用 @OneToMany注解可定义一对多关联.一对多关联可以是双向关联.
在EJB3规范中多对一这端几乎总是双向关联中的主体(owner)端,而一对多这端的关联注解为@OneToMany( mappedBy=...
            )

            @Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
}             

   Troop 通过troop
   属性和Soldier建立了一对多的双向关联.
   在mappedBy端不必也不能再定义任何物理映射

对于一对多的双向映射,如果要一对多这一端维护关联关系,你需要删除mappedBy元素并将多对一这端的 @JoinColumn的insertable和updatable设置为false.
很明显,这种方案不会得到什么明显的优化,而且还会增加一些附加的UPDATE语句.

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}
   通过在被拥有的实体端(owned entity)增加一个外键列来实现一对多单向关联是很少见的,也是不推荐的.
   我们强烈建议通过一个联接表(join table)来实现这种关联(下一节会对此进行解释).
   可以通过@JoinColumn注解来描述这种单向关联关系.       
@Entity
public class Customer implements Serializable {
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="CUST_ID")
    public Set<Ticket> getTickets() {
    ...
}

@Entity
public class Ticket implements Serializable {
    ... //no bidir
原创粉丝点击