hibernate一対多(one-to-many)双方向関連


一対多(one-to-many)双方向関連インスタンス(Department-Employee)
ここでの一対の多双方向関連付けは、ドメインモデル(実体オブジェクトモデル)上の概念である、リレーショナルデータベースでは、外部キー参照関係のみが存在し、常に「many」側が「one」側を参照するので、冗長データを除去することができる、上リレーショナルデータベースは実際には多対一または一対一の一方向関連付けのみをサポートするためである.エンティティ(クラスとクラスの間)の様々な関係の中で、数の多対一の一方向関連関係はデータベース中の外部キー参照関係と最も一致している.
私の前の文章の多対一に基づいて修正します.
1.Departmentエンティティクラスを変更するには、次の手順に従います.
package com.reiyen.hibernate.domain
public class Department {

	private int id;
	private String name;
	private Set<Employee> emps; 

   //setter getter  
}

 2.Departmentを変更します.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="com.reiyen.hibernate.domain">
	<class name="Department" >
		<id name="id" >
			<generator class="native" />
		</id>
		<property name="name" />
		<set name="emps">
		<key column="depart_id" />
		<one-to-many class="Employee"/>
		</set>
	</class>
</hibernate-mapping>

要素の属性name:マッピング対象の永続化クラスの属性名を設定、ここではDepatmentクラスのemps属性とする.
要素の2つのサブ要素:
:関連する永続化クラスに対応するテーブルの外部キーを設定します.ここではEmployeeテーブルのdepart_idフィールド
:関連する永続化クラスを設定します.ここではEmployee.
Hibernateは、上記の構成情報に基づいて、次の情報を取得します.
要素はDepartmentクラスのemps属性がjavaであることを示す.util.セットタイプ
サブエレメントは、empsコレクションに格納されているEmployeeオブジェクトのセットを示します.
サブエレメントは、employeeテーブルが外部キーdepart_を介していることを示します.idはdepartmentテーブルを参照する.
 
 3.残りはそのままで、テストクラスは次のとおりです.
public class Many2One {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Department depart = add();
		Department department = queryDepart(depart.getId());
                //department.getEmps();3
// System.out.println("emp size:" + department.getEmps().size());4  
	}

	static Department queryDepart(int departId) {
		Session s = null;
		Transaction tx = null;
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			Department depart = (Department) s.get(Department.class, departId);
			 System.out.println("emp size:" + depart.getEmps().size());//1      
                         // System.out.println("emps class:" + depart.getEmps().getClass());   //2 
                         // Hibernate.initialize(depart.getEmps());
			tx.commit();
			return depart;
		} finally {
			if (s != null)
				s.close();
		}
	}

	static Department add() {
		Session s = null;
		Transaction tx = null;
		try {
			Department depart = new Department();
			depart.setName("department name");
			
			Employee employee1 = new Employee();
			employee1.setDepartment(depart); //     :          
			employee1.setName("employee1 name2");
			
			Employee employee2 = new Employee();
			employee2.setDepartment(depart); //     :          
			employee2.setName("employee2 name2");

       // Set<Employee> set = new HashSet<Employee>();
		    //    set.add(employee1);
		    //	set.add(employee2);
		    //	depart.setEmps(set);
			
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(depart);
			s.save(employee1);
			s.save(employee2);
			tx.commit();
			return depart;
		} finally {
			if (s != null)
				s.close();
		}
	}
}

コンソールの印刷情報は次のとおりです.
Hibernate: insert into Department (name) values (?) Hibernate: insert into Employee (name, depart_id) values (?, ?) Hibernate: insert into Employee (name, depart_id) values (?, ?) Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=? Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=?
emp size:2
次のようにデータベースに記録されます.
mysql> select * from employee; +----+-----------------+-----------+ | id | name            | depart_id | +----+-----------------+-----------+ |  1 | employee1 name2 |         1 | |  2 | employee2 name2 |         1 | +----+-----------------+-----------+ 2 rows in set (0.00 sec) mysql> select * from department; +----+-----------------+ | id | name            | +----+-----------------+ |  1 | department name | +----+-----------------+ 1 row in set (0.00 sec)
 
オブジェクトモデルは変更されましたが、データベース関係モデルは変更されていません.
 
テストプログラムの注釈部分を削除し、同時に「オブジェクトモデルを作成する」という注釈を削除すると、正しく実行できますが、コンソールには2つの更新文が印刷され、データベースが2回の更新操作を実行したことを示し、効率に影響があります.以下に示します.
Hibernate: insert into Department (name) values (?) Hibernate: insert into Employee (name, depart_id) values (?, ?) Hibernate: insert into Employee (name, depart_id) values (?, ?)Hibernate: update Employee set depart_id=? where id=? Hibernate: update Employee set depart_id=? where id=? Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=? Hibernate: select emps0_.depart_id as depart3_1_, emps0_.id as id1_, emps0_.id as id2_0_, emps0_.name as name2_0_, emps0_.depart_id as depart3_2_0_ from Employee emps0_ where emps0_.depart_id=? emp size:2
 
4.怠惰ロード分析:
(1)プログラム中に1と表記されているプログラム注釈を削除した場合、コンソールは以下のように情報を印刷する.
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
この場合はDepartmentオブジェクトのみがクエリされ、対応するEmployeeはクエリされません.
(2)プログラムの中で1と表記されているプログラムの注釈を削除し、同時に2と表記されている前の注釈を削除した場合、プログラムを実行し、コンソール印刷情報は以下の通りである.
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=? emps class:class org.hibernate.collection.PersistentSet
このとき、Hibernateがhashsetを自分で書いたPersistentSetに置き換えていることがわかり、怠惰なロード機能を実現することができます.同時にdepartmentが呼び出される.getEmps();hibernateは、集合エージェントオブジェクトの参照を取得しただけで、集合オブジェクトを埋め込むためにデータベースをクエリーしません.この問題を検証するためにさらにテストすることもできます.プログラムに1とマークされているプログラム注釈を削除し、3とマークされている文の前の注釈を削除すると、プログラムが正常に動作していることがわかりますが、4とマークされている文の前の注釈を削除してプログラムを実行すると、次のような異常が放出されます.
 org.hibernate.LazyInitializationException : failed to lazily initialize a collection of role: com.reiyen.hibernate.domain.Department.emps, no session or session was closed
(3)departmentオブジェクトクエリを行う場合,departmentのテーブル構造からもこのDepartmentオブジェクトに対応するEmployeeがあるかどうかは判断できないが,なぜ一対一クエリではない場合にも,関連するオブジェクトを一度にクエリするのではないか.これは、関連するオブジェクトをクエリーすると、データが多いため効率に深刻な影響を及ぼすため、一対一ではなく、いずれにしてもオブジェクトから1つしかなく、一度にクエリーするとあまり影響がないため、hibernateは対応するEmployeeがあると仮定し、集合エージェントオブジェクトの戻りを直接作成した(オブジェクトを参照して先に渡す)ためです.データが必要なときにデータベースをクエリーして、効率を高めます.