2015年11月7日 星期六

Component映射(細粒度、粗粒度) (Hibernate3.x 十四)

之前的映射,都是簡單的映射(Basic O/R Mapping),也就是一張表映射成一個persistent class
還可以用細粒度(fine-grained),也就是一張表映射成多個persistent class,被細化出來的類別,可以用Component把這幾個類別組合起來
相對於細粒度,也有人說一張表映射成一個persistent class是粗粒度
官網的連結在這


※準備資料

drop table chess;
CREATE TABLE CHESS ( 
    CHESS_NO NUMBER(10,0), 
    NAME VARCHAR2(10 BYTE), 
    PRICE NUMBER(5,0), 
    PRODUCT_DATE DATE, 
    SALARY NUMBER(7,0), 
    COMPANY VARCHAR2(20 BYTE), 
    CONSTRAINT "CHESS_PK" PRIMARY KEY ("CHESS_NO")
);
    
COMMENT ON TABLE CHESS  IS '棋表';
COMMENT ON COLUMN CHESS.CHESS_NO IS '編號';
COMMENT ON COLUMN CHESS.NAME IS '名稱';
COMMENT ON COLUMN CHESS.PRICE IS '價錢';
COMMENT ON COLUMN CHESS.PRODUCT_DATE IS '製造日期';
COMMENT ON COLUMN CHESS.SALARY IS '薪水';
COMMENT ON COLUMN CHESS.COMPANY IS '天殺的外派公司名稱';
    
Insert into CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) values (35,'孔明棋',20,to_date('21-7月 -15','DD-MON-RR'),50000,'小棋玩具社');
INSERT INTO CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) VALUES (7,'象棋',50,to_date('18-7月 -15','DD-MON-RR'),45000,'大毛會社');
Insert into CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) values (8,'西洋棋',120,to_date('18-7月 -15','DD-MON-RR'),30000,'豬超人童玩');
Insert into CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) values (9,'跳棋',30,to_date('18-7月 -15','DD-MON-RR'),15000,'小兔跳棋會社');
INSERT INTO CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) VALUES (10,'圍棋',40,to_date('18-7月 -15','DD-MON-RR'),22000,'大牛圍棋社');
INSERT INTO CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) VALUES (12,'軍棋',99,to_date('18-7月 -15','DD-MON-RR'),17000,'軍啊公司');
Insert into CHESS (CHESS_NO,NAME,PRICE,PRODUCT_DATE,SALARY,COMPANY) values (14,'五子棋',35,to_date('18-7月 -15','DD-MON-RR'),24000,'五子棋協會');

※細粒度就是再進一步的劃分,譬如編號、名稱、價錢、製造日期是屬於產品的基本資訊,還有薪水、外派公司屬於其他資訊,這樣就可以分成三類,也就是資料的更細一步的劃分


※XML設定

Chess.java
private Integer chessNo;
private ChessBasic xxx;
private ChessOther ooo;
//setter/getter...

ChessBasic.java
private String name;
private Integer price;
private Date productDate;
//setter/getter...

ChessOther.java
private Integer salary;
private String company;
//setter/getter...

Chess.hbm.xml
<class name="vo.Chess" table="CHESS">
    <id name="chessNo" type="java.lang.Integer">
        <column name="CHESS_NO" />
        <generator class="assigned" />
    </id>
    
    <component name="xxx" class="vo.ChessBasic">
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="price" type="java.lang.Integer">
            <column name="PRICE" />
        </property>
        <property name="productDate" type="java.util.Date">
            <column name="PRODUCT_DATE" />
        </property>
    </component>
    
    <component name="ooo" class="vo.ChessOther">
        <property name="salary" type="java.lang.Integer">
            <column name="SALARY" />
        </property>
        <property name="company" type="java.lang.String">
            <column name="COMPANY" />
        </property>
    </component>
</class>

※增加component把屬性包起來而已,name名稱要對應好
Test.java
try {
    List<Chess> list = HibernateUtil2.getSession().createQuery("from Chess").list();
    for (Chess ch : list) {
        System.out.println(ch.getChessNo());
        System.out.println(ch.getXxx().getName());
        System.out.println(ch.getOoo().getCompany());
    }
} catch (Exception e) {
    System.err.println("例外錯誤!");
    e.printStackTrace();
} finally {
    if (s.isOpen()) {
        s.close();
    }
}

※記得hibernate.cfg.xml的mapping resource要加


※Annotation設定

Chess.java
@Entity
@Table(name = "CHESS", schema = "c##scott")
public class Chess {
    private Integer chessNo;
    private ChessBasic xxx;
    private ChessOther ooo;
    
    @Id
    @Column(name = "CHESS_NO", unique = true, nullable = false)
    public Integer getChessNo() {
        return chessNo;
    }
    
    public void setChessNo(Integer chessNo) {
        this.chessNo = chessNo;
    }
    
    //其他setter/getter都不用annotation
}

ChessBasic.java
@Embeddable
@AttributeOverrides({
    @AttributeOverride(name = "name", column = @Column(name = "NAME")),
    @AttributeOverride(name = "price", column = @Column(name = "PRICE")),
    @AttributeOverride(name = "productDate", column = @Column(name = "PRODUCT_DATE"))
})
public class ChessBasic {
    private String name;
    private Integer price;
    private Date productDate;
    //setter/getter...且完全不用annotation
}

ChessOther.java
@Embeddable
@AttributeOverrides({
    @AttributeOverride(name = "salary", column = @Column(name = "SALARY")),
    @AttributeOverride(name = "company", column = @Column(name = "COMPANY"))
})
public class ChessOther {
    private Integer salary;
    private String company;
    //setter/getter...且完全不用annotation
}

※測試類和XML設定一樣

※如果不設@Embeddable,會報「org.hibernate.MappingException: Could not determine type for: vo.ChessBasic, at table: CHESS, for columns: [org.hibernate.mapping.Column(xxx)]」的錯

※如果資料庫和Class name一樣,可以不設@AttributeOverrieds,也就是只有@Embeddable; 這一點和@Column一樣

※@AttributeOverride因為沒有xml,所以在這設定對應關係,Chess.java也不用特別設定什麼,自然就能從getter的回傳類型找到

※如果資料庫和Class name一樣,annotation設定還蠻方便的

沒有留言:

張貼留言