Hibernate映射多对一关系

Hibernate映射多对一关系

背景

一个项目item,对应多个Bid。

简单单向版

Hibernate

Bid 到 item之间简单关联,先不考虑其他情况。

Hibernate 之间的映射如下:

<class name="Bid" table="BID">
...
<many-to-one
    name="item"
    column="ITEM_ID"
    class="Item"
    not-null="true"/>
</class>

此处为单向表,BID表中item_id为ITEM表主键的一个外键。其中not null则指定bid必须关联一个item。

JPA

public class Bid{
…
@ManyToOne(targetEntity = auction.model.Item.class)
@JoinColumn(name=”ITEM_ID”,nullable=false)
private Item item;
…
}

targetEntity一般而言是可选的,,对于字段而言是隐式的,在复杂的领域模型很有用。JoinColumn也可选,默认外键名称为item加id,用下划线相连,另外,外键为not null,就需要使用nullable=false。

双向关联

Hibernate

增加ITEM到BID的一对多的关联。

ITEM不仅需要添加BID之间的关联,还需要添加相应BID的脚手架代码如下:

public class Item{
    ...
    private set bids = new HashSet();
    public void setBids(set bids){
        this.bids = bids;
    }
    public set getBids(){
        return bids;
    }
    //脚手架代码在Entity中
    public void addBid(Bid bid){
        bid.setItem(this);//实现相互托管关联
        bids.add(bid);
    }
     ...
}

一对多的基本映射:

<class name="item" table="ITEM">
    ...
    <set name=bids>
        <key column="ITEM_ID"/>
        <one-to-many class="Bid"/>
    </set>
</class>

从上述可看出,用one-to-many映射了集合的内容,且该值类型包含了对示例的引用。可以看出,到集合的引用set不需要table属性。其中key映射的是Bid表的外键列,即已经在关系的另一侧映射的同一个列。

现在出现一个问题,此时的关联实际上还是属于两个单向关联。由于之前的单项关联指定了not null =true,这里映射到同一个外键不需要重复指定。此时需要指定两个关联由哪一方进行控制,inverse属性告诉hibernate,集合是many-to-one关联在另一侧的一个镜像:

<class name="item" table="ITEM">
    ...
    <set name=bids inverse=true>
        <key column="ITEM_ID"/>
        <one-to-many class="Bid"/>
    </set>
</class>

说明:

由inverse控制被控制方,此处只有bid.setItem()时,才能达到自己想要的。

需要转换反向端时,many-to-one没有inverse属性,但是可以用update=false、insert=false有效忽略任何update、insert语句。

JPA

用jpa注解这个反向集合

public class Item{
    ...
    @oneToMany(mappedBy = "item")
    private Set(Bid) bids = new HashSet<Bid>();
    ...
}

OneToOne,OneToMany,ManyToMany上才有mappedBy,定义在被拥有一方,指向拥有方,拥有方能够自动维护被拥有方的关系。

mappedBy跟joinColumn/JoinTable总是处于互斥的一方。

级联删除

级联是有方向性的,定义在关联对象的被关联字段上面,同inverse。

Hibernate

<set name="bids" inverse="true" cascade="save-update,delete">
...

JPA

public class Item {
    @OneToMany(cascade={
        CasecadeType.PERSIST,
        CasecadeType.MERGE,
        CasecadeType.REMOVE},
        mappedBy = "item")
    private Set(Bid) bids = new HashSet<Bid>();
}

孤儿删除

只有在一对多的环境下才有孤儿删除。
在一对多的关系中,可以将一的一方认为是父方.将多的一方认为是子方.孤儿删除:在解除了父子关 系的时候.将子方记录就直接删除。

在XML中开启

<set name="bids" inverse="true" casecade="save-update,delete,delete-orphan">
...

Hibernate扩展使用

public class Item{
    @OneToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE,Cascade.Type.REMOVE},mappedBy = "item")
    @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Set<Bid> bids = new HashSet<Bid>();
}