Hibernate一对一主键关联(基于annotation注解方式)

前言:使用@OneToOne注解可以建立实体bean之间的一对一的关联. 一对一关联有三种情况: 一是关联的实体都共享同样的主键, 二是其中一个实体通过外键关联到另一个实体的主键 (注意要模拟一对一关联必须在外键列上添加唯一约束). 三是通过关联表来保存两个实体之间的连接关系 (注意要模拟一对一关联必须在每一个外键上添加唯一约束).

(1)共享主键来进行一对一关联映射(单向)

例子:我们用一个男人只有一个妻子为例

import javax.persistence.*;

@Entity
@Table(name = "husband")
public class Husband {

	private int id;
	private String name;
	private Wife wife;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	//记得cascade一定要有哦要不同时保存时不会保存wife对象
	@OneToOne(cascade = { CascadeType.ALL })
	@PrimaryKeyJoinColumn
	public Wife getWife() {
		return wife;
	}

	public void setWife(Wife wife) {
		this.wife = wife;
	}

}
---------------------------
@Entity
@Table(name = "wife")
public class Wife {

	private int id;
	private String name;

	@Id
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}
--------------------------
测试方法
	public static void installData() {
		SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();

		Husband husband = new Husband();
		husband.setName("丁元伟");
		Wife wife = new Wife();
		wife.setName("不知道");
		husband.setWife(wife);

		session.save(husband); //只需保存husband就可以同时保存wife了

		tx.commit();
		/*Hibernate:   生成的sql语句
		    insert 
		    into
		        husband
		        (id, name) 
		    values
		        (null, ?)
		Hibernate: 
		    select
		        wife_.id,
		        wife_.name as name5_ 
		    from
		        wife wife_ 
		    where
		        wife_.id=?
		Hibernate: 
		    insert 
		    into
		        wife
		        (name, id) 
		    values
		        (?, ?)*/
	}
//查询时只需查询husband就可以把wife也查出来


(2) 主键来进行一对一关联映射(双向)
  Husband类不变同上
  Wife类有所改变
@Entity
@Table(name = "wife")
public class Wife {

	private int id;
	private String name;

	private Husband husband;

	@Id
	@GenericGenerator(name = "pkGenerator", strategy = "foreign", parameters = { @Parameter(name = "property", value = "husband") })
	@GeneratedValue(generator = "pkGenerator")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@OneToOne(cascade = CascadeType.ALL, mappedBy = "wife")
	@PrimaryKeyJoinColumn
	public Husband getHusband() {
		return husband;
	}

	public void setHusband(Husband husband) {
		this.husband = husband;
	}

}


----------------测试代码save
	public static void installData() {
		SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();

		Husband husband = new Husband();
		husband.setName("丁元伟");
		Wife wife = new Wife();
		wife.setName("不知道");
		husband.setWife(wife);//这边得写
		wife.setHusband(husband); //这边也得写
		session.save(husband); //只需保存husband就可以同时保存wife了

		tx.commit();

	}
-----------------find
	public static void findDate() {
		SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();
		/*
		因为mappedBy是定义在classes中,即classes类不负责维护级联关系.即维护者是student.所以,
		1.要将clsses的数据,赋给student,即用student的setClasses()方法去捆定class数据;
		2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.
		*/
		/*Husband husband = (Husband) session.get(Husband.class, 1);

		System.out.println(husband.getName());

		Wife wife = husband.getWife();
		System.out.println(wife.getName());*/
		//上下都可行
		Wife wife = (Wife) session.get(Wife.class, 1);
		System.out.println(wife.getName());
		Husband husband = wife.getHusband();
		System.out.println(husband.getName());
		tx.commit();
	}


(3)一对一外键双向关联(没有中间表)
@Entity
@Table(name = "husband")
public class Husband {

	private int id;
	private String name;
	private Wife wife;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	//记得cascade一定要有哦要不同时保存时不会保存wife对象
	@OneToOne(cascade = CascadeType.ALL, mappedBy = "husband")//必须有cascade

	public Wife getWife() {
		return wife;
	}

	public void setWife(Wife wife) {
		this.wife = wife;
	}

}

---------------------------------------
@Entity
@Table(name = "wife")
public class Wife {

	private int id;
	private String name;
	private Husband husband;

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@OneToOne(cascade = CascadeType.ALL) //必须有cascade
	@JoinColumn(name = "husband_id")
	public Husband getHusband() {
		return husband;
	}

	public void setHusband(Husband husband) {
		this.husband = husband;
	}

}
---------------------------------------
	public static void installData() {
		SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();

		tx.begin();
		Husband husband = new Husband();
		husband.setName("张三");
		Wife wife = new Wife();
		wife.setName("如花");
		wife.setHusband(husband);
		husband.setWife(wife);
		session.save(husband);
		//或session.save(wife); 但双方得相互设入对方
		tx.commit();
	}
-------------------------------------

下面查询时如果只查一方都会带出另一方内容(left outer join关联所以得设置为延迟加载)
/*
		因为mappedBy是定义在classes中,即classes类不负责维护级联关系.即维护者是student.所以,
		1.要将clsses的数据,赋给student,即用student的setClasses()方法去捆定class数据;
		2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.
		*/
		Husband husband = (Husband) session.get(Husband.class, 1);

		System.out.println(husband.getName());

		Wife wife = husband.getWife();
		System.out.println(wife.getName());
		//上下都可行
		/*Wife wife = (Wife) session.get(Wife.class, 1);
		System.out.println(wife.getName());
		Husband husband = wife.getHusband();
		System.out.println(husband.getName());*/


4)一对一外键单向关联(没有中间表)

单向关联就是一边不设关联
//这边没有设置关联操作其他的和上面3的一样

@Entity
@Table(name = "husband")
public class Husband {

	private int id;
	private String name;


	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(name = "name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


}


(5)hibernate 注解一对一关系 关联表关联

请参考
http://gyfbao.blog.sohu.com/166353836.html

测试关联表时如出现下面这个错,需先主键类持久化或保存相对应的另一个非主键类
org.hibernate.PropertyValueException: not-null property references a null or transient value:

你可能感兴趣的:(annotation)