JPA持久化API,针对数据库的增删改查(六):关联关系映射;单向1-1;单向N-1;单向1-N;单向N-N关联及实例

关联关系映射
客观世界中的对象很少有孤立存在的,例如老师,往往与被授课的学生存在关联关系,如果已经得到某个老师的实体,
	那么可以获取该老师对应的全部学生。反过来,如果已经得到一个学生实体,
	也应该可以访问该学生对应的老师——这种实例之间的相互访问就是关联关系.
	
关联关系是面向对象分析,面向对象设计最重要的是知识,JPA完全可以正常处理这种关联关系。
	如果映射得当,JPA的关联映射将可以大大简化持久层数据的访问。关联关系大致有如下两个分类;
		1.单向关联:只需要访问关联端。例如,只能通过老师访问学生,或者只能通过学生访问老师,这种关联关系就是单向关联
		2.双向关联:关联的两端可以相互访问。例如,老师和学生之间可以相互访问,这种关联关系就是双向关联
		
关联关系还存在数量上的区别,假如说有一个老师负责某个班的全部课程,那么这个班级的所有学生都只对应一个老师,
	从学生到老师的角度来看,这种关联关系被称为N-1关联;反过来看,老师到学生的关联被称为1-N关联。
	对于多个商店顾客,售货员的关系,一个售货员可以向多个顾客提供服务,一个顾客也可能通过多个售货员购买商品,
	那么这种关系就被称为N-N关联
	
	从关联关系的数量上来看,单向关联可分为:
		一对一 一对多 多对一 多对多 
	从关联关系的数量上来看,双向关联可分为:
		一对一 一对多 多对多
		
双向关系里没有N-1,因为双向关系1-N和N-1是完全相同的

从两个关联实体的源代码来看,如果两个实体之间存在双向关联,那么两个实体都需要提供属性来访问关联实体;
	如果两个实体之间只存在单向关联,那么两个实体只需要在一方提供属性来访问关联实体即可
1.单向N-1关联
N-1是非常常见的关联关系,最常见的父子关系也是N-1关联,单向的N-1关联只需从N的一段可以访问1的一端
单向N-1关系比如多个人对应同一个住址,只需从人实体端可以找到对应的地址实体,无需关心某个地址的全部住户
为了让实体支持这种单向的关联关系,程序应该在N的一端的实体类中增加一个属性,该属性引用1的一端的关联实体

eg:多个人对应同一个地址(N-1)

1.新建数据库

新建数据库person_table:字段为personId,name,age,addressId(外键)
新建数据库address_table:字段为addressId,detail

2.新建主控Person人员类变为实体

@Entity
@Table(name = "persion_table")
public class Persion {

	@Id
	private int persionId;
	@Column
	private String name;
	@Column
	private int age;
	
	//多个人对应一个地址
	/**cascade 联级策略(当进行主表操作的时候,从表中的数据同样也会进行操作) ALL:将所有持久化操作都级联到关联实体还支持merge,persist,refresh,remove四个属性
	 * fetch 抓取策略 EAGER一次性发送多条sql语句进行查询 LAZY延迟加载,使用的时候才进行查询
	 * optional 指定关联关系是否可选
	 * targetEntity 指定关联实体的类名。在默认情况下,JPA将通过反射来判断关联实体的类名
	 */
	@ManyToOne(
			cascade = CascadeType.ALL,
			fetch = FetchType.LAZY,
			optional = false,
			targetEntity = Address.class
	)
	//连接字段 重命名 在数据库中那个字段体现连接关系
	@JoinColumn(
			name = "addressId",
			nullable = false
	) 
	private Address address;
	
	
	public Persion() {
		
	}
	
	public int getPersionId() {
		return persionId;
	}
	public void setPersionId(int persionId) {
		this.persionId = persionId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}
}

3.新建Address地址类变为实体

@Entity
@Table(name = "address_table")
public class Address {

	@Id
	private int addressId;
	@Column
	private String detail;
	
	public Address() {
		
	}
	
	public int getAddressId() {
		return addressId;
	}
	public void setAddressId(int addressId) {
		this.addressId = addressId;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}
}

4.测试类

public class RelationTest {

	private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("company");	
	
	@Test
	public void testMantToOne() {
		//数据库关联关系 单向N-1
		
		EntityManager em = emf.createEntityManager();
		//地址实体
		Address add = new Address();
		add.setAddressId(1);
		add.setDetail("天津");
		
		//人员实体
		Persion per1 = new Persion();
		per1.setPersionId(1);
		per1.setName("张三");
		per1.setAge(20);
		per1.setAddress(add);

		Persion per2 = new Persion();
		per2.setPersionId(2);
		per2.setName("李四");
		per2.setAge(30);
		per2.setAddress(add);
		
		try {
			em.getTransaction().begin();
			em.persist(add);
			em.persist(per1);
			em.persist(per2);
			em.getTransaction().commit();
			
			System.out.println(per1.getName());
			System.out.println(per1.getAddress().getDetail());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			em.getTransaction().rollback();
		}finally {
			em.close();
		}
		
	}
}
2.单向1-1关联
对于单向1-1关联关系,需要在实体类里为关联实体的引用属性增加setter和getter方法。从实体类的代码上来看,
	单向1-1与单向N-1没有丝毫区别,因为N的一端,或者1的一端都是直接访问关联实体,
	只需要增加关联实体属性的setter和getter方法即可

eg:一个人对应一个地址(1-1)
1.新建数据库

新建数据库person_table:字段为personId,name,age,addressId(外键)
新建数据库address_table:字段为addressId,detail

2.新建主控Person人员类变为实体

@Entity
@Table(name = "persion_table")
public class Persion1t1 {

	@Id
	private int persionId;
	@Column
	private String name;
	@Column
	private int age;
	
	@OneToOne(cascade = CascadeType.ALL,optional = false,
			fetch = FetchType.LAZY,targetEntity = Address1t1.class)
	@JoinColumn(name = "addressId",nullable = false)
	private Address1t1 address;
	
	public Persion1t1() {}
	
	public int getPersionId() {
		return persionId;
	}
	public void setPersionId(int persionId) {
		this.persionId = persionId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public Address1t1 getAddress() {
		return address;
	}

	public void setAddress(Address1t1 address) {
		this.address = address;
	}	
}

3.新建Address住址类变为实体

@Entity
@Table(name = "address_table")
public class Address1t1 {
	
	@Id
	private int addressId;
	@Column
	private String detail;
	
	public Address1t1() {}
	
	public int getAddressId() {
		return addressId;
	}
	public void setAddressId(int addressId) {
		this.addressId = addressId;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}
}

4.测试类

public class RelationTest {

	private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("company");	
	
	@Test
	public void testOneToOne() {
		
		EntityManager em =emf.createEntityManager();
			
		try {
			Address1t1 addr = new Address1t1();
			addr.setAddressId(2);
			addr.setDetail("晋中市");
			Persion1t1 per1 = new Persion1t1();
			per1.setPersionId(3);
			per1.setName("王五");
			per1.setAge(40);
			per1.setAddress(addr);
		
			em.getTransaction().begin();
			em.persist(per1);
			em.getTransaction().commit();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			em.getTransaction().rollback();
		}finally {
			em.close();
		}
	}
}
3.单向1-N关联
单向1-N关联的实体类需要做点小调整,实体类需要使用集合属性。因为1的一端需要访问N个关联实体,
	那么多个关联实体就需要以集合(Set)形式出现。从这个意义上来看,1-N(实际上还包括N-N)都需要增加一个Set类型的属性,
	该属性记录了他的多个关联实体.
使用Set类型的属性来记录关联实体时,最好使用泛型来记录关联实体的实体类,以便JPA可以通过反射来确定关联实体的类型。
	当然,也可以通过@OneToMany增加targetEntity属性来明确指定关联实体的类型

eg:一个人部门对应多名员工(1-N)
1.新建数据库

新建数据库emp:字段为empno,ename,sal,deptno(外键)
新建数据库dept:字段为deptno,dname,loc,empno

2.新建主控dept部门类变为实体

@Entity
@Table(name = "dept")
public class Dept1tN{

	@Id
	private int deptno;
	private String dname;
	private String loc;
	
	//一个部门多名员工(集合)
	@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,
			targetEntity = Emp1tN.class)
	@JoinColumn(name = "deptno")
	private Set<Emp1tN> emps = new HashSet<Emp1tN>();

	public Dept1tN() {}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	public String getDname() {
		return dname;
	}

	public void setDname(String dname) {
		this.dname = dname;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	public Set<Emp1tN> getEmps() {
		return emps;
	}

	public void setEmps(Set<Emp1tN> emps) {
		this.emps = emps;
	}
}

3.新建emp员工类变为实体

@Entity
@Table(name = "emp")
public class Emp1tN{

	@Id
	private int empno;
	private String ename;
	private int sal;
	
	public Emp1tN() {}
	
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public int getSal() {
		return sal;
	}
	public void setSal(int sal) {
		this.sal = sal;
	}
}

4.测试

public class RelationTest {

	private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("company");	
	
	@Test
	public void TestOneToMany() {
		
		EntityManager em = emf.createEntityManager();
		
		Dept1tN dept = new Dept1tN();
		dept.setDeptno(1);
		dept.setDname("研发部");
		dept.setLoc("天津市");
		
		Emp1tN emp1 = new Emp1tN();
		emp1.setEmpno(1);
		emp1.setEname("张三");
		emp1.setSal(4000);

		Emp1tN emp2 = new Emp1tN();
		emp2.setEmpno(2);
		emp2.setEname("李四");
		emp2.setSal(5000);

		Emp1tN emp3 = new Emp1tN();
		emp3.setEmpno(3);
		emp3.setEname("王五");
		emp3.setSal(7000);
		
		//创建一个封装员工实体的集合对象
		Set<Emp1tN> emps = new HashSet<Emp1tN>();
		emps.add(emp1);
		emps.add(emp2);
		emps.add(emp3);
		dept.setEmps(emps);
		
		try {
			em.getTransaction().begin();
			em.persist(dept);
			em.getTransaction().commit();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			em.getTransaction().rollback();
		}finally {
			em.close();
		}
	}
}
4.单向N-N关联

eg:多个人对应多个住址(N-N)
1.1.新建数据库

新建数据库person_table:字段为personId,name,age,addressId(外键)
新建数据库address_table:字段为addressId,detail,personId(外键)

2.新建主控Person人员类变为实体

@Entity
@Table(name="person_table")
public class PersonNtN {
	@Id
	private int id;
	private String name;
	private int age;
	@ManyToMany(
			cascade = CascadeType.ALL,
			fetch = FetchType.LAZY,
			targetEntity = AddressNtN.class
	)
	@JoinTable(
			name = "person_address",
			joinColumns = @JoinColumn(name="personId"),
			inverseJoinColumns = @JoinColumn(name="addressId")
	)
	private Set<AddressNtN> addresses = new HashSet<AddressNtN>();
	public PersonNtN() {

	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Set<AddressNtN> getAddresses() {
		return addresses;
	}
	public void setAddresses(Set<AddressNtN> addresses) {
		this.addresses = addresses;
	}
}

3.创建Address住址类变为实体

@Entity
@Table(name="address_table")
public class AddressNtN {
	@Id
	private int id;
	private String detail;
	public AddressNtN() {
	
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}	
}

4.测试类

public class RelationTest {

	private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("company");	

	@Test
	public void testConnection() {
		
		EntityManager em = emf.createEntityManager();
		try {
			em.getTransaction().begin();
			Query query = em.createQuery("select p.persionId,p.name,p.age,"
					+ "a.detail from Person as p inner join"
					+ "p.address as a");
			List result = query.getResultList();
			em.getTransaction().commit();
			System.out.println(result);
			System.out.println(result.size());
			

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值