package cn.itcast.k_query_hql;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Department.class)// 新增Hibernate實體類(載入對應的對映檔案)
			.addClass(Employee.class)// 新增Hibernate實體類(載入對應的對映檔案)
			.buildSessionFactory();

	// 準備資料
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 儲存一些部門資料
		for (int i = 1; i <= 10; i++) {
			Department department = new Department();
			department.setName("開發部_" + i);
			session.save(department);
		}

		// 儲存一些員工資料
		for (int i = 1; i <= 20; i++) {
			Employee employee = new Employee();
			employee.setName("李XX_" + i);
			session.save(employee);
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 使用HQL查詢
	// HQL: Hibernate Query Language.
	// 特點:
	// >> 1,與SQL相似,SQL中的語法基本上都可以直接使用。
	// >> 2,SQL查詢的是表和表中的列;HQL查詢的是物件與物件中的屬性。
	// >> 3,HQL的關鍵字不區分大小寫,類名與屬性名是區分大小寫的。
	// >> 4,SELECT可以省略.
	@Test
	public void testHql() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------
		String hql = null;

		// 1,簡單的查詢
		// hql = "FROM Employee";
		// hql = "FROM Employee AS e"; // 使用別名
		// hql = "FROM Employee e"; // 使用別名,as關鍵字可省略。別名用來防止關鍵字衝突,推薦使用別名

		// 2,帶上過濾條件的(可以使用別名):Where
		// hql = "FROM Employee WHERE id<10";
		// hql = "FROM Employee e WHERE e.id<10";
		// hql = "FROM Employee e WHERE e.id<10 AND e.id>5";

		// 3,帶上排序條件的:Order By
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name";
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC";
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";

		// 4,指定select子句(不可以使用select *)
		// hql = "SELECT e FROM Employee e"; // 相當於"FROM Employee e"
		// hql = "SELECT e.name FROM Employee e"; // 只查詢一個列,返回的集合的元素型別就是這個屬性的型別
		// hql = "SELECT e.id,e.name FROM Employee e"; // 查詢多個列,返回的集合的元素型別是Object陣列
		// hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; // 可以使用new語法,指定把查詢出的部分屬性封裝到物件中

		// 5,執行查詢,獲得結果(list、uniqueResult、分頁 )
		// Query query = session.createQuery("FROM Employee e WHERE id<3");
		// query.setFirstResult(0);
		// query.setMaxResults(10);
		// // List list = query.list(); // 查詢的結果是一個List集合
		// Employee employee = (Employee) query.uniqueResult();// 查詢的結果是唯一的一個結果,當結果有多個,就會拋異常
		// System.out.println(employee);

		// 6,方法鏈
		List list = session.createQuery(//
				"FROM Employee")//
				.setFirstResult(0)//
				.setMaxResults(10)//
				.list();

		// // ----- 執行查詢
		// List list = session.createQuery(hql).list();
		//
		// ----- 顯示結果
		for (Object obj : list) {
			if (obj.getClass().isArray()) {
				System.out.println(Arrays.toString((Object[]) obj));
			} else {
				System.out.println(obj);
			}
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void testHql_2() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------
		String hql = null;

		// 1,聚集函式:count(), max(), min(), avg(), sum()
		// hql = "SELECT COUNT(*) FROM Employee"; // 返回的結果是Long型的
		// hql = "SELECT min(id) FROM Employee"; // 返回的結果是id屬性的型別
		// Number result = (Number) session.createQuery(hql).uniqueResult();
		// System.out.println(result.getClass());
		// System.out.println(result);

		// 2,分組: Group By ... Having
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name";
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name HAVING count(e.id)>1";
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e WHERE id<9 GROUP BY e.name HAVING count(e.id)>1";
		// ---
		// hql = "SELECT e.name,COUNT(e.id) " + //
		// "FROM Employee e " + //
		// "WHERE id<9 " + //
		// "GROUP BY e.name " + //
		// "HAVING count(e.id)>1 " + //
		// "ORDER BY count(e.id) ASC";
		// ---
		// hql = "SELECT e.name,COUNT(e.id) AS c " + //
		// "FROM Employee e " + //
		// "WHERE id<9 " + //
		// "GROUP BY e.name " + //
		// "HAVING count(e.id)>1 " + // 在having子句中不能使用列別名
		// "ORDER BY c ASC"; // 在orderby子句中可以使用列別名

		// 3,連線查詢 / HQL是面向物件的查詢
		// >> 內連線(inner關鍵字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e JOIN e.department d";
		// hql = "SELECT e.id,e.name,d.name FROM Employee e INNER JOIN e.department d";
		// >> 左外連線(outer關鍵字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e LEFT OUTER JOIN e.department d";
		// >> 右外連線(outer關鍵字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e RIGHT JOIN e.department d";
		// 可以使用更方便的方法
		// hql = "SELECT e.id,e.name,e.department.name FROM Employee e";

		// 4,查詢時使用引數
		// >> 方式一:使用'?'佔位
		// hql = "FROM Employee e WHERE id BETWEEN ? AND ?";
		// List list = session.createQuery(hql)//
		// .setParameter(0, 5)// 設定引數,第1個引數的索引為0。
		// .setParameter(1, 15)//
		// .list();

		// >> 方式二:使用變數名
		// hql = "FROM Employee e WHERE id BETWEEN :idMin AND :idMax";
		// List list = session.createQuery(hql)//
		// .setParameter("idMax", 15)//
		// .setParameter("idMin", 5)//
		// .list();

		// 當引數是集合時,一定要使用setParameterList()設定引數值
		// hql = "FROM Employee e WHERE id IN (:ids)";
		// List list = session.createQuery(hql)//
		// .setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })//
		// .list();

		// 5,使用命名查詢
		// Query query = session.getNamedQuery("queryByIdRange");
		// query.setParameter("idMin", 3);
		// query.setParameter("idMax", 10);
		// List list = query.list();

		// 6,update與delete,不會通知Session快取
		// >> Update
		// int result = session.createQuery(//
		// "UPDATE Employee e SET e.name=? WHERE id>15")//
		// .setParameter(0, "無名氏")//
		// .executeUpdate(); // 返回int型的結果,表示影響了多少行。
		// System.out.println("result = " + result);
		// >> Delete
		int result = session.createQuery(//
				"DELETE FROM Employee e WHERE id>15")//
				.executeUpdate(); // 返回int型的結果,表示影響了多少行。
		System.out.println("result = " + result);

		// ----- 執行查詢並顯示結果
		// // List list = session.createQuery(hql).list();
		// for (Object obj : list) {
		// if (obj.getClass().isArray()) {
		// System.out.println(Arrays.toString((Object[]) obj));
		// } else {
		// System.out.println(obj);
		// }
		// }

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void testHql_DML() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 第一次顯示名稱
		Employee employee = (Employee) session.get(Employee.class, 13);
		System.out.println(employee.getName());

		// update與delete,不會通知Session快取
		int result = session.createQuery(//
				"UPDATE Employee e SET e.name=? WHERE id>10")//
				.setParameter(0, "無名氏3")//
				.executeUpdate(); // 返回int型的結果,表示影響了多少行。

		// 第二次顯示名稱
		// 在update或delete後,需要refresh(obj)一下以獲取最新的狀態
		session.refresh(employee);
		System.out.println(employee.getName());

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

5、多種查詢方式——qbc

package cn.itcast.k_query_qbc;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Department.class)// 新增Hibernate實體類(載入對應的對映檔案)
			.addClass(Employee.class)// 新增Hibernate實體類(載入對應的對映檔案)
			.buildSessionFactory();

	// 準備資料
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 儲存一些部門資料
		for (int i = 1; i <= 10; i++) {
			Department department = new Department();
			department.setName("開發部_" + i);
			session.save(department);
		}

		// 儲存一些員工資料
		for (int i = 1; i <= 20; i++) {
			Employee employee = new Employee();
			employee.setName("李XX_" + i);
			session.save(employee);
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 使用QBC方式查詢:Query By Criteria
	@Test
	public void testQBC() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 建立Criteria物件
		Criteria criteria = session.createCriteria(Employee.class);
		// 增加過濾條件
		criteria.add(Restrictions.ge("id", 1));
		criteria.add(Restrictions.le("id", 5));
		// 增加排序條件
		criteria.addOrder(Order.desc("name"));
		criteria.addOrder(Order.desc("id"));
		// 執行查詢
		// criteria.setFirstResult(0);
		// criteria.setMaxResults(100);
		// criteria.uniqueResult();
		// criteria.list()
		List list = criteria.list();
		// 顯示結果
		for (Object obj : list) {
			if (obj.getClass().isArray()) {
				System.out.println(Arrays.toString((Object[]) obj));
			} else {
				System.out.println(obj);
			}
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

一、一對一的關聯關係對映(外來鍵 + 唯一)
       基於外來鍵的
                有外來鍵方:<many-to-one name="obj" class=".." column=".." unique="true"/>
                無外來鍵方:<one-to-one name=".." class=".." property-ref="obj"/>

        基於主鍵的
                有外來鍵方:<one-to-one ...>
                無外來鍵方:<one-to-one ...>

        操作:
                在採用基於外來鍵的方式時:只有有外來鍵方可以維護關聯關係。
                在採用基於主鍵的方式時:雙方都不可以維護關係。

二、繼承結構對映
        1,整個繼承結構使用一張表。列上不能有not-null="true"。
        2,每個類對應一張表,抽象類也對應表。
        3,每個具體類對應一張表,抽象類不對應表。

三、HQL語句
        與SQL的語法類似。
        HQL查詢的物件、屬性,所以寫的時候寫的是類名、屬性名。
        HQL的關鍵字不區分大小寫,類名與屬性名區分大小寫。
        語法:
                SELECT           別名/屬性名/表示式
                FROM              實體 AS 別名
                WHERE           過濾條件
                ORDER BY      排序條件

                SELECT           別名/屬性名/表示式
                FROM              實體 AS 別名
                WHERE           過濾條件
                GROUP BY     分組條件
                HAVING          分組後的結果的過濾條件
                ORDER BY     排序條件 
.