Hibernate One-To-One 关联

 

现实生活中,一对一(One To One)关系的实体比比皆是。比如,人和身份证的关系,人和社会属性的关系等。

在Hibernate中,OneToOne关系分为两种策略:主键关联和唯一外键关联。主键关联,就是两个一对一的实体共用相同的id。比如,人(Person)和身份证(IdCard),将Person的id主键,关联到IdCard的主键。这样,两个实体,就通过主键关联在一起了。唯一外键的含义也很明确。就是在Person实体中定义一个额外的字段,比如card_id,用这个字段外键关联到IdCard的主键id。

下面就让我们看看主键关联:

Person.java

public class Person {  
    private Integer id;  
    private String name;  
    private String sex;  
    private Integer age;  
    private Idcard idcard;  
    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public String getSex() {  
        return sex;  
    }  
    public void setSex(String sex) {  
        this.sex = sex;  
    }  
    public Integer getAge() {  
        return age;  
    }  
    public void setAge(Integer age) {  
        this.age = age;  
    }  
    public Idcard getIdcard() {  
        return idcard;  
    }  
    public void setIdcard(Idcard idcard) {  
        this.idcard = idcard;  
    }  


Idcard.java

 

public class Idcard {  
    private Integer id;  
    private String cardNum;  
    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer id) {  
        this.id = id;  
    }  
    public String getCardNum() {  
        return cardNum;  
    }  
    public void setCardNum(String cardNum) {  
        this.cardNum = cardNum;  
    }  
}  


以上是两个实体。

Person.hbm.xml

<!DOCTYPE hibernate-mapping  
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
<hibernate-mapping package="demo.hibernate.domain">  
   <class name="Person">  
       <id name="id" unsaved-value="null">  
            <!--在单独使用的时候,可以使用序列策略,这里对应的数据库是Oracle,不同的数据库,拥有不同的主键生成策略-->  
            <!--<generator class="sequence">-->  
                <!--<param name="sequence">seq_person</param>-->  
            <!--</generator>-->  
            <!--因为人和身份证是一对一关联,避免冗余的数据生成,采用主键相同的策略-->  
            <generator class="foreign">  
                <param name="property">idcard</param>  
            </generator>  
       </id>  
       <property name="name"/>  
       <property name="sex" />  
       <property name="age" />  
       <!--cascade=all :在插入一条Person信息的时候,可以插入一条Idcard。constrained=true:因为这里存在一个外键约束,person的主键,关联到idcard的主键-->  
       <!--这里lazy=false,这样,在抓取person信息的时候,就同时抓取了idcard。否则,如果lazy=proxy,这也是hibernate默认的抓取方式,这样你在获取person后再获取idcard,就  
       会报no Session 异常。在web开发中,可以开启openSessionInView,确保Session的生命周期延续到前台页面,lazy=false,对性能会有影响-->  
       <one-to-one name="idcard" cascade="none" constrained="true" lazy="false"></one-to-one>  
   </class>  
</hibernate-mapping>  

Idcard.hbm.xml

<?xml version="1.0"?>  
<!DOCTYPE hibernate-mapping  
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
<hibernate-mapping package="demo.hibernate.domain">  
   <class name="Idcard">  
       <id name="id" unsaved-value="null">  
            <generator class="sequence">  
                <param name="sequence">seq_person</param>  
            </generator>  
       </id>  
       <property name="cardNum"/>  
   </class>  
</hibernate-mapping>  


 

以上是Person.java和Idcard.java对应的映射文件。

public class PersonDao {  
  
    public Integer save(Person person){  
        Integer id = null;  
        try {  
            if(person == null){  
                return null;  
            }  
            Session s = HibernateUtils.getCurrentSession();  
            Transaction t = s.beginTransaction();  
            id = (Integer)s.save(person);  
            t.commit();  
        } catch (HibernateException e) {  
            throw new RuntimeException("保存person信息失败");  
        }finally {  
            HibernateUtils.closeSession();  
        }  
        return id;  
    }  
    public Person get(int id){  
        Person p = null;  
        try {  
            Session s = HibernateUtils.getCurrentSession();  
            p = (Person)s.get(Person.class, id);  
            return p;  
        } catch (HibernateException e) {  
            throw new RuntimeException("获取person信息失败");  
        } finally {  
            HibernateUtils.closeSession();  
        }  
    }  
  
    public List<Person> getPersonList(String name){  
        List<Person> persons = null;  
        try {  
            Session s = HibernateUtils.getCurrentSession();  
            StringBuilder hql = new StringBuilder("from Person");  
            Query q = null;  
            if(name != null && !name.isEmpty()){  
                hql.append("where name = :name");  
                q = s.createQuery(hql.toString());  
                q.setParameter("name",name);  
            }else {  
                q = s.createQuery(hql.toString());  
            }  
            persons = q.list();  
            return persons;  
        } catch (HibernateException e) {  
            throw new RuntimeException("获取person信息失败");  
        } finally {  
            HibernateUtils.closeSession();  
        }  
    }  
}  


 

上面是PersonDao.java,封装了对Person实体的基本操作。

public class TestPersonDao {  
    static Person person = null;  
    static Idcard idcard = null;  
    static PersonDao personDao = null;  
    static Integer personId = 21;  
    @BeforeClass  
    public static void init(){  
        initOne2One();  
    }  
    private static void initOne2One(){  
        idcard = new Idcard();  
        idcard.setCardNum("342401198911045870");  
        person = new Person();  
        person.setName("new");  
        person.setAge(12);  
        person.setSex("m");  
        person.setIdcard(idcard);  
        //这里注意,Person和Idcard是一对一关联。   
        //这里,在保存Person的时候,idcard是一个瞬时对象,未持久化。但是,配置的时候,cascade=all,   
        //这样,在保存Person对象的时候,hibernate会首先将idcard一并保存。   
        personDao = new PersonDao();  
    }  
    @Test  
    public void testSave(){  
        personId = personDao.save(person);  
        Assert.assertNotNull(personId);  
        Integer id1 = personDao.save(null);  
        Assert.assertNull(id1);  
    }  
    @Test  
    public void testGet(){  
        Person p = personDao.get(personId);  
        Assert.assertNotNull(p);  
        Assert.assertNotNull(p.getIdcard());  
        Assert.assertNotNull(p.getIdcard().getCardNum());  
    }  
    @Test  
    public void testGetPersonList(){  
        List<Person> persons = personDao.getPersonList(null);  
        //One-To-One:这里,就会出现一个N+1次查询的问题,   
        //因为One-To-One关联时,在Idcard中并不存在和person关联的信息,   
        //只有先查到person,然后再根据每一个person的id获取到与其关联的idcard。这样总共就做了N+1次查询。   
        //这样非常消耗性能   
        //@select * from person; 得到10条数据。   
        //接下来,做10次循环:@for 1 to 10 do select * from idcard d where d.id = person.id end for;   
    }  
}  


 

上面是PersonDao的测试类。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值