2015年12月31日 星期四

多對多單向FK關聯(關聯表無主鍵或其他欄位) (Hibernate3.x 三十一)

※準備工作

DROP TABLE PERSON_TOILET PURGE;
DROP TABLE TOILET PURGE;
DROP TABLE PERSON PURGE;
    
CREATE TABLE PERSON(
    PID NUMBER(5),
    PNAME VARCHAR(20),
    CONSTRAINT PERSON_PK PRIMARY KEY(PID)
);
    
CREATE TABLE TOILET(
    TID NUMBER(5),
    TNAME VARCHAR(20),
    CONSTRAINT TOILET_PK PRIMARY KEY(TID)
);
    
CREATE TABLE PERSON_TOILET(
    PERSON_ID NUMBER(5),
    TOILET_ID NUMBER(5),
    CONSTRAINT FK_PID FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PID) ON DELETE CASCADE,
    CONSTRAINT FK_TID FOREIGN KEY(TOILET_ID) REFERENCES TOILET(TID) ON DELETE CASCADE
);
    
CREATE SEQUENCE TOILET_SEQ;
CREATE SEQUENCE PERSON_SEQ;

※和二十九篇完全一樣

※XML設定

hibernate.cfg.xml

<session-factory>
    <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
    <property name="hibernate.connection.username">username</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <!-- <property name="hibernate.use_sql_comments">true</property> -->
    
    <!-- <property name="hibernate.connection.autocommit">true</property> -->
    <!-- <property name="hibernate.hbm2ddl.auto">update</property> -->
    
    <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <property name="hibernate.current_session_context_class">thread</property>
    
    <!-- <property name="hibernate.cache.use_second_level_cache">true</property> -->
    <!-- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> -->
    <!-- <property name="hibernate.QueryCacheEnabled">true</property> -->
    <!-- <property name="hibernate.cache.use_query_cache">true</property> -->
    
    <mapping resource="vo/Toilet.hbm.xml" />
    <mapping resource="vo/Person.hbm.xml" />
    
    <!-- <class-cache usage="read-only" class="vo.Emp"/> -->
</session-factory>



Person.java

public class Person {
    private Integer pid;
    private String pname;
    private Set<Toilet> toilets = new HashSet<>();
    // setter/getter...
}



Toilet.java

public class Toilet {
    private Integer tid;
    private String tname;
    // setter/getter...
}

※因為是單向,所以Toilet不用關聯Person


Person.hbm.xml

<class name="vo.Person" table="PERSON">
    <id name="pid" type="java.lang.Integer">
        <column name="PID" />
        <generator class="sequence">
            <param name="sequence">PERSON_SEQ</param>
        </generator>
    </id>
    
    <property name="pname" type="java.lang.String" column="PNAME" />
    
    <set name="toilets" table="PERSON_TOILET" cascade="delete" lazy="false">
        <key column="PERSON_ID" />
        <many-to-many column="TOILET_ID" class="vo.Toilet" />
    </set>
</class>



Toilet.hbm.xml

<class name="vo.Toilet" table="TOILET">
    <id name="tid" type="java.lang.Integer">
        <column name="TID" />
        <generator class="sequence">
            <param name="sequence">TOILET_SEQ</param>
        </generator>
    </id>
    
    <property name="tname" type="java.lang.String" column="TNAME" />
</class>



新增測試

Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
    Toilet t1 = new Toilet();
    t1.setTname("便所1號");
    
    Toilet t2 = new Toilet();
    t2.setTname("便所2號");
    
    Toilet t3 = new Toilet();
    t3.setTname("便所3號");
    
    Person p1 = new Person();
    p1.setPname("掃便所英俠");
    
    Person p2 = new Person();
    p2.setPname("茅坑王");
    
    // 掃便所英俠可以上廁所1~3號
    p1.getToilets().add(t1);
    p1.getToilets().add(t2);
    p1.getToilets().add(t3);
    
    // 茅坑俠可以上廁所1、3號
    p2.getToilets().add(t1);
    p2.getToilets().add(t3);
    
    s.save(p1);
    s.save(p2);
    tx.commit();
} catch (Exception e) {
    tx.rollback();
    System.err.println("例外錯誤!");
    e.printStackTrace();
} finally {
    if (s.isOpen()) {
        s.close();
    }
}



修改測試

Person person = (Person) s.get(Person.class, 161);// 掃便所英俠的ID
person.setPname("吸茅坑大王");
    
for (Toilet toilet : person.getToilets()) {
    toilet.setTname("廁" + toilet.getTname().substring(1));
}
    
s.update(person);
tx.commit();



查詢測試

Person p = (Person) s.get(Person.class, 161);// 掃便所英俠的ID
s.close();
System.out.println(p.getPname());
    
// 必需在Person.hbm.xml設定lazy="false"
for (Toilet toi : p.getToilets()) {
    System.out.println(toi.getTname());
}



刪除測試

Person pp = (Person) s.get(Person.class, 167);
s.delete(pp);
tx.commit();// 關聯表不會刪

※cascade不要設delete相關,怪怪的



※Annotation設定

Person.java

@Entity
@Table
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX")
    @SequenceGenerator(name = "XXX", sequenceName = "PERSON_SEQ")
    private Integer pid;
    
    private String pname;
    
    @ManyToMany
    @LazyCollection(value = LazyCollectionOption.FALSE)
    @JoinTable(name = "PERSON_TOILET", joinColumns = { @JoinColumn(name = "PERSON_ID", updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "TOILET_ID", updatable = false) })
    private Set toilets = new HashSet<>();
    
    // setter/getter...
}



Toilet.java

@Entity
@Table
public class Toilet {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX")
    @SequenceGenerator(name = "XXX", sequenceName = "TOILET_SEQ")
    private Integer tid;
    
    private String tname;
    // setter/getter...
}

※刪除的時候,我將cascade整個拿掉,才和XML一樣

沒有留言:

張貼留言