hibernate关联映射之一对一

作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要。hibernate在关联方法的实现很简单。下面我们先来看看一对一的做法:

不多说了,我们直接上代码:

两个实体类,TUser和TPassport:

public class TUser implements Serializable{

	private static final long serialVersionUID = 1L;
	private int id;
	private int age;
	private String name;
	private TPassport passport;
        //省略Get/Set方法
}
public class TPassport implements Serializable{

	private static final long serialVersionUID = 1L;
	private int id;
	private String serial;
	private int expiry;
	private TUser user;
        //省略Get/Set方法
}

  下面我们看一下映射文件有什么不同:

<hibernate-mapping package="org.hibernate.tutorial.domain4">
	<class name="TUser" table="USER4">
		<id name="id" column="id">
			<generator class="native" />
		</id>
		<property name="name" type="java.lang.String" column="name"/>
		<property name="age" type="java.lang.Integer" column="age"/>
		<one-to-one name="passport" class="TPassport" 
					cascade="all" outer-join="true" />
	</class>
</hibernate-mapping>

  这里我们看到有一个新标签,one-to-one,它表明当前类与所对应的类是一对一的关系,cascade是级联关系,all表明无论什么情况都进行级联,即当对TUser类进行操作时,TPassport也会进行相应的操作,outer-join是指是否使用outer join语句。

我们再看另外一个TPassport的映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain4">
	<class name="TPassport" table="passport4">
		<id name="id" column="id">
			<generator class="foreign" >
				<param name="property">user</param>
			</generator>
		</id>
		<property name="serial" type="java.lang.String" column="serial"/>
		<property name="expiry" type="java.lang.Integer" column="expiry"/>
		<one-to-one name="user" class="TUser" constrained="true" />
	</class>
</hibernate-mapping>

  这里我们重点看到generator的class值,它为foreign表明参照外键,而参照哪一个是由param来进行指定,这里表明参照User类的id。而one-to-one标签中多了一个constrained属性,它是告诉hibernate当前类存在外键约束,即当前类的ID根据TUser的ID进行生成。

下面我们直接上测试类,这次测试类没有用JUnit而是直接Main方法来了:

public static void main(String[] args) {
		
		Configuration cfg = new Configuration().configure();
		SessionFactory sessionFactory = cfg.buildSessionFactory();
		Session session = sessionFactory.openSession();
		
		session.beginTransaction();
		
		TUser user = new TUser();
		user.setAge(20);
		user.setName("shunTest");
		
		TPassport passport = new TPassport();
		passport.setExpiry(20);
		passport.setSerial("123123123");
		
		passport.setUser(user);
		user.setPassport(passport);
		
		session.save(user);
		
		session.getTransaction().commit();
		
	}

  代码很简单,就不说了。我们主要看这里:

session.save(user);

  这里为什么我们只调用一个save呢,原因就在我们的TUser映射文件中的cascade属性,它被设为all,即表明当我们对TUser进行保存,更新,删除等操作时,TPassport也会进行相应的操作,所以这里我们不用写session.save(passport)。我们看到后台:

Hibernate: insert into USER4 (name, age) values (?, ?)
Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?)

  它打印出两个语句,证明hibernate确定帮我们做了这个工作。

下面我们再来一个测试类,测试查询:

public static void main(String[] args) {
		Configuration cfg = new Configuration().configure();
		SessionFactory sessionFactory = cfg.buildSessionFactory();
		Session session = sessionFactory.openSession();
		
		TUser user = (TUser)session.load(TUser.class,new Integer(3));
		System.out.println(user.getName()+":"+user.getPassport().getSerial());
		
	}

  这里我们通过查询出TUser类,取到TPassport对象。

我们可以看到hibernate的SQL语句是:

Hibernate: select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?

  我们看到语句当中有left outer join,这是因为我们前面在one-to-one当中设了outer-join="true",我们试着把它改成false,看到SQL语句如下:

Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?
Hibernate: select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?

  现在是分成两条来查了,根据第一条查出的ID再到第二条查出来。

也许很多人会问为什么测试的时候不用TPassport查出TUser呢,其实也可以的,因为它们是一对一的关系,谁查谁都是一样的。

猜你喜欢

转载自cxshun.iteye.com/blog/1056012