程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> jpa的雙向一對多和雙向一對一關聯關系

jpa的雙向一對多和雙向一對一關聯關系

編輯:C++入門知識

jpa的雙向一對多和雙向一對一關聯關系


在分享之前先給大家看兩個異常,應該說這一類的異常還是很常見的,主要原因是jar包沖突

異常1:

java.lang.NoSuchFieldError: INSTANCE
	at org.hibernate.type.BasicTypeRegistry.(BasicTypeRegistry.java:94)
	at org.hibernate.type.TypeResolver.(TypeResolver.java:59)
	at org.hibernate.cfg.Configuration.(Configuration.java:250)
	at org.hibernate.cfg.Configuration.(Configuration.java:302)
	at org.hibernate.cfg.AnnotationConfiguration.(AnnotationConfiguration.java:108)
	at org.hibernate.ejb.Ejb3Configuration.(Ejb3Configuration.java:107)
	at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:124)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:52)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:34)
	at org.lxh.util.JpaUtil.(JpaUtil.java:10)
	at org.lxh.test.Test.testInsert(Test.java:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)

這個異常主要出現在hibernate3.6或更高版本,解決辦法是刪除hibernate-annotations.jar和hibernate-commons-annotations.jar

因為hibernate3.6包裡已經包含以上兩包了


異常2:

Caused by: java.lang.NoSuchMethodError: javax.persistence.OneToMany.orphanRemoval()Z  
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1912)  
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:796)  
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:707)  
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:4035)  
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3989)  
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1398)  
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1375)  
    at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:717)  
    at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:188)  
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)  
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)  
    ... 65 more

該異常也是jar包沖突導致,主要還是出現在hibernate3.6或更高版本,解決辦法是刪除ejb3-persistence.jar

一 一對多關聯關系

異常的問題說了,下面進入正題,昨天研究了jpa的基本使用,這次分享下jpa的一對多和一對一關聯關系,這一部分也和hibernate大體類似,只是在配置上稍有差異。一對多是很常見的關聯關系,在jpa中一對多關聯關系由多的一方維護,下面以員工和部門為例來表現一對多的這種關系

1. 部門的員工的實體類

package org.lxh.info;

import java.util.*;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Depart {
	private Integer id;
	private String departName;
	private String departNum;
	private Set emp;
    @Id @GeneratedValue
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
    @Column(length=50,nullable=false,unique=true)
	public String getDepartName() {
		return departName;
	}

	public void setDepartName(String departName) {
		this.departName = departName;
	}

	public String getDepartNum() {
		return departNum;
	}

	public void setDepartNum(String departNum) {
		this.departNum = departNum;
	}
    @OneToMany(cascade={CascadeType.REMOVE,CascadeType.PERSIST},mappedBy="depart")
	public Set getEmp() {
		return emp;
	}

	public void setEmp(Set emp) {
		this.emp = emp;
	}
}

一對多關聯使用的注解是@OneToMany,cascade就不解釋了,mappedBy屬性主要用在關系被維護端,在這裡就是一的這一邊,mappedBy="depart"表明在關系維護端對應的屬性為depart

package org.lxh.info;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Employee {
	private Integer id;
	private String num;
	private String name;
	private Depart depart;
       @Id @GeneratedValue
	public Integer getId() {
		return id;
	}

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

	public String getNum() {
		return num;
	}

	public void setNum(String num) {
		this.num = num;
	}
        @Column(nullable=false,length=50)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
        @ManyToOne
        @JoinColumn(name="depart_id")
	public Depart getDepart() {
		return depart;
	}

	public void setDepart(Depart depart) {
		this.depart = depart;
	}
}

Employee作為關系維護端負責外鍵字段或外鍵記錄的更新,體現在數據庫中則為從表,裡面含有一個外鍵和depart相對應。@JoinColumn用來指定外鍵的列名,從程序可以看出這裡的外鍵列名為depart_id


2 使用單元測試保存數據

package org.lxh.test;

import static org.junit.Assert.*;

import java.util.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import org.lxh.info.Depart;
import org.lxh.info.Employee;
import org.lxh.util.JpaUtil;

public class Test {

	@org.junit.Test
	public void testInsert() {
		EntityManager em=null;
		EntityTransaction tx=null;
		try{
		    em=JpaUtil.getEntityManager();
	            tx=em.getTransaction();
		    tx.begin();
		    Depart d=new Depart();
		    d.setDepartName("質量管理部");
		    d.setDepartNum("DP0001");
		    
		    Employee e=new Employee();
		    e.setDepart(d);
		    e.setName("李明");
		    e.setNum("C0001");
		    
		    Set emps=new HashSet();
		    emps.add(e);
		    
		    d.setEmp(emps);;
		    
		    em.persist(d);
		    
			tx.commit();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(em!=null){
				em.close();
			}
		}
		
	}
	
}

下面是打印出的sql語句:

Hibernate: 
    insert 
    into
        Depart
        (departName, departNum) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Employee
        (depart_id, name, num) 
    values
        (?, ?, ?)

這樣數據就保存成功了,其他操作暫時忽略,大家可以自己寫一寫


二 一對一關聯關系

一對一關聯使用的場合相對較少,好多人都會把兩個表並為一個,字段看起來很多但是操作起來著實方便

1 先來看看實體,我的例子是人員和人員信息詳細表的對於關系

package org.lxh.info;

import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "m_users")
public class User {
	
	private int id;
	private String name;
	private Date birthday;
	private Sex sex;
	private UserDetails userDetails;
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	@Column(length=20,nullable=false) 
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
        @Temporal(TemporalType.DATE)
	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
    @Enumerated(EnumType.STRING)
    @Column(length=5,nullable=false)
	public Sex getSex() {
		return sex;
	}

	public void setSex(Sex sex) {
		this.sex = sex;
	}
        @OneToOne(cascade=CascadeType.ALL)
        @JoinColumn(name="detailsId")
        public UserDetails getUserDetails() {
		return userDetails;
	}

	public void setUserDetails(UserDetails userDetails) {
		this.userDetails = userDetails;
	}
}

對於一對一關聯關系,代碼編寫者可以根據自已的意願或業務需要選擇任意一方作為關系維護方,我這裡選擇的人員信息詳細作為關系維護方

package org.lxh.info;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToOne;


@Entity
public class UserDetails {
	private Integer id;
	private String introduce;
	private String cardNum;
	private User user;
        @Id @GeneratedValue
   	public Integer getId() {
 		return id;
 	}

 	public void setId(Integer id) {
		 this.id = id;
	}
        @Lob
	public String getIntroduce() {
 		return introduce;
 	}

 	public void setIntroduce(String introduce) {
		this.introduce = introduce;
	 }

 	public String getCardNum() {
		 return cardNum;
	}

	 public void setCardNum(String cardNum) {
		this.cardNum = cardNum;
 	}
        @OneToOne(mappedBy="userDetails",cascade=CascadeType.MERGE)
 	public User getUser() {
		return user;
 	}

	public void setUser(User user) {
 		this.user = user;
	}

}


到這裡實體就編寫好了


2 一對一的保存操作

@org.junit.Test
	public void testInsert() {
		EntityManager em=null;
		EntityTransaction tx=null;
		try{
			em=JpaUtil.getEntityManager();
			tx=em.getTransaction();
			tx.begin();
			
			User u=new User();
			u.setBirthday(new Date());
			u.setName("潘玮柏");
			u.setSex(Sex.MAN);
			
			UserDetails detail=new UserDetails();
			detail.setCardNum("562923");
			detail.setIntroduce("暫無");
			detail.setUser(u);
			
			u.setUserDetails(detail);
			em.persist(u);
		    
			tx.commit();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(em!=null){
				em.close();
			}
		}
		
	}

打印出來的sql語句如下:

Hibernate: 
    insert 
    into
        UserDetails
        (cardNum, introduce) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        m_users
        (birthday, name, sex, detailsId) 
    values
        (?, ?, ?, ?)

是不是很簡單呢得意


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved