Re: hibernateを利用してはいけない5つのシチュエーション

ヤドカリデンキ商会さん (id:yad-EL) に「執拗につっこみ」などと言われてしまったとです...
でもでも,ひがさんや通りすがりさんからコメントを頂いたから連日書いているだけで,決して「執拗につっこみ」しようと思っているわけではないのですが...
そんなわけで (どんなわけで?),今日はこのネタは控えようかと思っていた矢先,id:digo さんからコメントを頂いてしまいました.

hibernateの件ですが、なんらかの理由でgetterで取得する値とsetterで設定される値に差がある場合に起きるかも・・・
以前、「フィールドがnullだったら””を返すgetter」みたいなのを作ったら、毎回dirty checkに引っかかって更新が走ってしまう現象にハマったことがありました。

おぉ,この脳内補完はいけてそう.これなら無条件 (っていうのは変ですが) に更新されても不思議はありません.
さっそく試してみましょう.


例によって Model なんですが,firstNamelastName の getter は null の場合に空文字列を返します.

package hoge;

public class Model {

    private int id = -1;
    private String firstName;
    private String lastName;
    private Magazine magazine;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName == null ? "" : firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName == null ? "" : lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Magazine getMagazine() {
        return magazine;
    }

    public void setMagazine(Magazine magazine) {
        this.magazine = magazine;
    }

    public String toString() {
        return getFirstName() + " " + getLastName();
    }
}

そしてテストメソッド.

    public void testHibernateTransaction() throws Exception {
        Configuration config = new Configuration();
        SessionFactory factory = config.configure("hibernate3.cfg.xml").buildSessionFactory();
        Session session = factory.openSession();
        Transaction tx = session.beginTransaction();
        Model model = (Model) session.get(Model.class, new Integer(1));
        tx.commit();
    }

問い合わせというか主キーを指定して取得しているだけ.とてもシンプル♪
そして用意したデータの lastNamenull にしておきます.
これによって発行された SQL.じゃーん.

Hibernate: select 
               model0_.id as id0_, 
               model0_.firstName as firstName0_0_, 
               model0_.lastName as lastName0_0_, 
               model0_.contract as contract0_0_ 
           from 
               Model model0_ 
           where 
               model0_.id=?
Hibernate: update 
               Model 
           set 
               lastName=? 
           where 
               id=?

更新されました!! \(^o^)/


っていうか,これで喜んでいいわけじゃありませんね.
そうですか,こういうことをやっちゃったんでしょうかねぇ?
ちなみに,このような getter を使いたい場合には,Hibernate にプロパティ (getter/setter) ではなくフィールドを使わせることができます.
マッピングファイルで次のように

<?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 auto-import="false" package="hoge">
    <class name="Model" dynamic-update="true">
        <id name="id" unsaved-value="-1">
            <generator class="assigned"/>
        </id>

        <property name="firstName" access="field"/>
        <property name="lastName" access="field"/>
        <many-to-one name="magazine" column="contract"/>
    </class>
</hibernate-mapping>

<property> 要素の access 属性で "field" を指定するだけ.
これで先のテストメソッドを実行すると...

Hibernate: select 
               model0_.id as id0_, 
               model0_.firstName as firstName0_0_, 
               model0_.lastName as lastName0_0_, 
               model0_.contract as contract0_0_ 
           from 
               Model model0_ 
           where 
               model0_.id=?

更新されなくなります.
いちいちプロパティごとに指定するのが面倒なら <hibernate-mapping> 要素の default-access 属性でまとめて指定することも可.


フィールドアクセスは入門記ではお馴染みですね.
なんせ,getter/setter 作らないでやってましたからねぇ...
心より恥じる.