Hibernate學習(1)

JPA常用註解

請參考:http://1194867672-qq-com.iteye.com/blog/1730513

下面根據經驗談談Hibernate的一對多,多對一問題。

(一)雙向一對多的用法

可參考:http://blog.csdn.net/lxl_family/article/details/26523757

雙向一對多關係,一是關係維護端(owner side),多是關係被維護端(inverse side)。數據庫中的表一般都是相互關聯的,它們通過foreign key產生關係。在關係被維護端需要通過@JoinColumn建立外鍵列指向關係維護端的主鍵列

   @Entity  //設置一個類爲實體類</span>
   @JsonIgnoreProperties(value={"orderItems "}) </span>
   @Table(name="Order") //作用:設置實體類對應的表,常與@Entity一起使用</span>
   public class Order implements Serializable {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   private Long id;
   @JsonIgnore
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
   private transient String strbegin;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")</span>
    private Date begindate;
  
   private Set<OrderItem> orderItems = new HashSet<OrderItem>();
   。。。。 
   @OneToMany(mappedBy="order",cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
   @OrderBy(value = "id ASC") 
   public Set<OrderItem> getOrderItems() { 
   return orderItems; 
   }
  //其他get set方法省略
 } 
 public class OrderItem implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    private String itenName;
    private Order order; //不用再根據表結構定義order_id屬性 
	。。。。 
	@ManyToOne(cascade=CascadeType.REMOVE,optional=false) 
	@JoinColumn(name = "order_id",referencedColumnName="id") //OrderItem表中的order_id字段與order表中的id關聯 
	public Order getOrder() {
	return order; 
	}
	}


@OrderBy(value = "id ASC") 指明加載OrderItem 時按id 的升序排序
 
@OneToMany的屬性
1>targetEntity
定義關係類的類型,默認是該成員屬性對應的類類型,所以通常不需要提供定義
 
2>mappedBy
定義類之間的雙向關係。如果類之間是單向關係,不需要提供定義如果類和類之間形成雙向關係,我們就需要使用這個屬性進行定義,否則可能引起數據一致性的問題
該屬性的值是“多”方class裏的“一”方的變量名
 
3>cascade
該屬性定義類和類之間的級聯關係。定義的級聯關係將被容器視爲對當前類對象及其關聯類對象採取相同的操作,而且這種關係是遞歸調用的。舉個例子:Order OrderItem有級聯關係,那麼刪除Order時將同時刪除它所對應的OrderItem對象。而如果OrderItem還和其他的對象之間有級聯關係,那麼這樣的操作會一直遞歸執行下去。
 
cascade的值只能從CascadeType.PERSIST(級聯新建)、CascadeType.REMOVE(級聯刪除)、CascadeType.REFRESH(級聯刷新)、CascadeType.MERGE(級聯更新)中選擇一個或多個。還有一個選擇是使用CascadeType.ALL,表示選擇全部四項。
 
4>fetch
可選擇項包括:FetchType.EAGERFetchType.LAZY。前者表示關係類(本例是OrderItem )在主類(本例是Order)加載的時候同時加載,後者表示關係類在被訪問時才加載。默認值是FetchType.LAZY
 
@JoinColumn(name = "order_id" ,referencedColumnName="id")註釋指定OrderItem映射表的order_id列作爲外鍵與Order 映射表的主鍵列id關聯。
 
@ManyToOne:指明OrderItem和Order之間爲多對一關係。
 
@ManyToOne註釋有四個屬性:targetEntity、cascade、fetch 和optional,前三個屬性的具體含義和@OneToMany的同名屬性相同,但@ManyToOne的fetch 屬性默認值是FetchType.EAGER
 
optional屬性是定義該關聯類是否必須存在值爲false 時,關聯類雙方都必須存在,如果關係被維護端不存在,查詢的結果爲null。值爲true 時, 關係被維護端可以不存在,查詢的結果仍然會返回關係維護端,在關係維護端中指向關係被維護端的屬性爲nulloptional屬性的默認值是true。optional 屬性實際上指定關聯類與被關聯類的join 查詢關係,如optional=false 時join 查詢關係爲inner join, optional=true 時join 查詢關係爲left join下面代碼片斷解釋如下:
 
有一點需要強調:當業務方法需要把一個實體Bean作爲參數返回給客戶端時,除了實體Bean本身需要實現Serializable 接口之外,如果關聯類(OrderItem)是延遲加載,還需在返回實體Bean之前通過訪問關聯類的方式加載關聯類(見下例)。否則在客戶端訪問關聯類時將會拋出加載例外。
    public Order getOrderByID(Integer orderid) {
        Order order = em.find(Order.class, orderid);        
       //!!!!!因爲是延遲加載,通過執行size()這種方式獲取訂單下的所有訂單項
        order.getOrderItems().size();
       return order;
     }
 
另外不管是否延遲加載,通過join fetch 關聯語句都可顯式加載關聯類,如下例:
 
    public List getAllOrder() {
         Query query = em.createQuery("select DISTINCT o from Order o inner
join fetch o.orderItems order by o.orderid");
         List result = query.getResultList();
        return result;
     }
通常後臺返回的數據都需要轉換成JSON字符串,以下三個註解都是用於JSON轉換。
 @JsonIgnoreProperties(value={"OrderItems"})      忽略實體類中的關聯類

@JsonIgnore 也可以直接在屬性上Ignore

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 對屬性進行格式轉換,一般用於時間等特殊格式。

如果不處理,可能報錯:

jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:143)
//Json轉換死循環

org.springframework.orm.hibernate3.HibernateQueryException: could not resolve property
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not initialize proxy - no Session (through reference chain。。。)

(二)Hql的關聯查詢

1、從One的一方關聯到Many的一方:

查找出球員所屬的球隊,可以使用以下語句:

SELECT DISTINCT t FROM Order t JOIN t.OrderItems p where p.ItemName LIKE :name
或者使用以下語句:

SELECT DISTINCT t FROM Order t,IN(t.OrderItems) p WHERE p.ItemName LIKE :name

上面兩條語句是等價的,產生的SQL語句如下:

select 
    distinct Order0_.id as id0_,  
    Order0_.ItemName as ItemName0_  
from 
    Order Order0_  
inner join 
    player OrderItem1_  
        on Order0_.id=OrderItem1_.Order_id  
where 
    OrderItems1_.ItemName like ?

從SQL語句中可以看到team inner join 到player。inner join要求右邊的表達式必須有返回值。

不能使用以下語句:

<span style="font-size:12px;">SELECT DISTINCT t FROM Order t  WHERE t.OrderItem.ItemName LIKE :ItemName </span>

不能使用t.OrderItems.ItenName這樣的方式從集合中取值,要使用join或者in才行。

2、從Many的一方關聯到One的一方:

查找出某個球隊下的所有球員,可以使用以下查詢語句:

<span style="font-size:12px;">SELECT p FROM OrderItem p JOIN p.Order t WHERE t.id = :id </span>

或者使用以下語句

SELECT p FROM OrderItem p, IN(p.Order) t WHERE t.id = :id 
這兩條查詢語句是等價的,產生的SQL語句如下:(產生了兩條SQL)

Hibernate:  
    select 
        OrderItem0_.id as id1_,  
        OrderItem0_.ItemName as ItemName1_,  
        OrderItem0_.Order_id as Order3_1_  
    from 
        OrderItem OrderItem0_  
    inner join 
        Order Order1_  
            on OrderItem0_.Order_id=Order1_.id  
    where 
        Order1_.id=?  
Hibernate:  
    select 
        Order0_.id as id2_0_,  
        Order0_.ItemName as ItemName2_0_  
    from 
        Order Order0_  
    where 
        Order0_.id=? 

從Many關聯到One的查詢,還可以使用以下的查詢語句:
SELECT p FROM OrderItem p WHERE p.Order.id = :id 
這條語句產生的SQL如下:(產生了兩條SQL)

		SELECT p FROM OrderItem p WHERE p.Order.id = :id 
		
		Hibernate:  
    select 
        OrderItem0_.id as id1_,  
        OrderItem0_.name as name1_,  
        OrderItem0_.Order_id as Order3_1_  
    from 
        OrderItem OrderItem0_  
    where 
        OrderItem0_.Order_id=?  
Hibernate:  
    select 
        Order0_.id as id0_0_,  
        Order0_.name as name0_0_  
    from 
        Order Order0 

以上從Many到One的關聯查詢都產生了兩條SQL,還可以使用join fetch只產生一條SQL語句。查詢語句如下:

SELECT p FROM OrderItem p JOIN FETCH p.Order t WHERE t.id = :id 

這條查詢語句產生的SQL如下:

		Hibernate:  
    select 
        OrderItem0_.id as id1_0_,  
        Order1_.id as id2_1_,  
        OrderItem0_.name as name1_0_,  
        OrderItem0_.Order_id as Order3_1_0_,  
        Order1_.name as name2_1_  
    from 
        OrderItem OrderItem0_  
    inner join 
        Order Order1_  
            on OrderItem0_.Order_id=Order1_.id  
    where 
        Order1_.id=? 

可參考:http://www.cnblogs.com/luxh/archive/2012/06/02/2531750.html




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章