正在加载...

hibernate入门使用系列 6-- annotation关系映射篇(上)

这讲OneToOne的用法。而且是基于主外键的关联。因为这个是实际开发中最最常见的。

这里先说明一下,我的java类的命名都以Test开头。而对应的对象名却没有用test开头。这里是为了更好的说明注视中的value到底是类名还是对象名。

先看java代码:

TestUser

package net.paoding.forum.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class TestUser
{
    String   id;
    String   username;
    TestCard card;

    /**
     * @return the id
     */
    @Id
    public String getId()
    {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id)
    {
        this.id = id;
    }

    /**
     * @return the username
     */
    public String getUsername()
    {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username)
    {
        this.username = username;
    }

    /**
     * @return the card
     */
   @OneToOne
    public TestCard getCard()
    {
        return card;
    }

    /**
     * @param card the card to set
     */
    public void setCard(TestCard card)
    {
        this.card = card;
    }

}

TestCard:

package net.paoding.forum.domain;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class TestCard
{
    String id;
    String cardNumber;

    /**
     * @return the id
     */
    @Id
    public String getId()
    {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id)
    {
        this.id = id;
    }

    /**
     * @return the cardNumber
     */
    public String getCardNumber()
    {
        return cardNumber;
    }

    /**
     * @param cardNumber the cardNumber to set
     */
    public void setCardNumber(String cardNumber)
    {
        this.cardNumber = cardNumber;
    }
}

这样子就是OneToOne了。这个是单向的关系,即:由TestCard控制TestUser。看sql语句就知道了。

hibernate自动生成的sql为:

drop table test_card cascade constraints;

drop table test_user cascade constraints;

create table test_card (
    id varchar2(255 char) not null,
    card_number varchar2(255 char),
    primary key (id)
);

create table test_user (
    id varchar2(255 char) not null,
    username varchar2(255 char),
    card_id varchar2(255 char),
    primary key (id)
);

alter table test_user add constraint FKB9A96B58A237D846 foreign key (card_id) references test_card;

个人认为,应该这样子理解OneToOne。

首先,他是用来申明在方法上的。(这句好似废话)

然后,他其实是用来描述这个方法的返回值的。即:描述TestCard的。也就是说:TestCard 为控制方。TestUser为被控方。那么对应的表中,testuser表有一个外键字段对应着testcard表中的一个主键。

这样,就好理解了。

上面的为单向关联。那么,双向关联呢?修改TestCard如下:

package net.paoding.forum.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class TestCard
{
    String   id;
    String   cardNumber;
    TestUser user;

    /**
     * @return the id
     */
    @Id
    public String getId()
    {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id)
    {
        this.id = id;
    }

    /**
     * @return the user
     */
    @OneToOne
    public TestUser getUser()
    {
        return user;
    }

    /**
     * @param user the user to set
     */
    public void setUser(TestUser user)
    {
        this.user = user;
    }

    /**
     * @return the cardNumber
     */
    public String getCardNumber()
    {
        return cardNumber;
    }

    /**
     * @param cardNumber the cardNumber to set
     */
    public void setCardNumber(String cardNumber)
    {
        this.cardNumber = cardNumber;
    }
}

这样,产生的sql为:

drop table test_card cascade constraints;

drop table test_user cascade constraints;

create table test_card (
        id varchar2(255 char) not null,
        card_number varchar2(255 char),
        user_id varchar2(255 char),
        primary key (id)
    );

create table test_user (
    id varchar2(255 char) not null,
    username varchar2(255 char),
    card_id varchar2(255 char),
    primary key (id)
);

alter table test_card add constraint FKB9A0FA9D7876DA66 foreign key (user_id) references test_user;

alter table test_user add constraint FKB9A96B58A237D846 foreign key (card_id) references test_card;

可以看到,当我双方都声明了OneToOne时候,也就达到了双向的One2One效果。但是很遗憾。Hibernate不知道你由哪边控制哪边,或者说由哪边来维护关系。所以,他生成的sql语句中可以看到,都有testcard和testuser是相互关联的,即:都有FK关联上堆放的PK。很明显,这个不是我们要的效果。

我们需要的是,po中能双向one2one,但是db中不需要。所以,我们需要修改一下。

修改TestCard.java代码:

package net.paoding.forum.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class TestCard
{
    String   id;
    String   cardNumber;
    TestUser user;

    /**
     * @return the id
     */
    @Id
    public String getId()
    {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id)
    {
        this.id = id;
    }

    /**
     * @return the user
     */
    @OneToOne(mappedBy="card")
    public TestUser getUser()
    {
        return user;
    }

    /**
     * @param user the user to set
     */
    public void setUser(TestUser user)
    {
        this.user = user;
    }

    /**
     * @return the cardNumber
     */
    public String getCardNumber()
    {
        return cardNumber;
    }

    /**
     * @param cardNumber the cardNumber to set
     */
    public void setCardNumber(String cardNumber)
    {
        this.cardNumber = cardNumber;
    }
}

注意annotation的部分。mappedBy就指出了此处返回的TestUser对应的test_user表中有一个指向TestUser的属性"card"的外键。可以看sql。

drop table test_card cascade constraints;

drop table test_user cascade constraints;

create table test_card (
    id varchar2(255 char) not null,
    card_number varchar2(255 char),
    primary key (id)
);

create table test_user (
    id varchar2(255 char) not null,
    username varchar2(255 char),
    card_id varchar2(255 char),
    primary key (id)
);

alter table test_user add constraint FKB9A96B58A237D846 foreign key (card_id) references test_card;

而这得"mappedBy=card"中的card是TestUser中的TestCard类型的成员变量名。这也就是为什么我要用Test修饰类名,而对象名却不用的理由。

或者,还可以这样子来理解OneToOne。

单向OneToOne中。声明了OneToOne这个Annotation的方法,他的返回值即:维护方。(主键方)

双向OneToOne中。在OneToOne中声明了mappedBy="xx"的,他的返回值即:被维护方。(外键方)