hibernateでone-to-oneを使うときの注意点?

December 16, 2009,
tags: hibernate java one-to-one


このエントリーをはてなブックマークに追加

hibernateをつかっていて若干つまっていました。
外部キー関連のone-to-oneで他のテーブルと関連させる際に、どうしても外部キーの値がとれない。。
例えば、userテーブルと、profileテーブルがあって一対一の関係の場合。

テーブルとかこんな感じ。

CREATE SCHEMA IF NOT EXISTS `nakajima` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ; USE `nakajima`;
#userテーブル
CREATE  TABLE IF NOT EXISTS `nakajima`.`web_user` (
 `id` INT UNSIGNED NOT NULL  AUTO_INCREMENT ,
 `email` VARCHAR(255) NULL ,
 `password` VARCHAR(255) NULL ,
 `flag` TINYINT UNSIGNED NOT NULL DEFAULT 1 ,
 PRIMARY KEY (`id`) )
ENGINE = InnoDB;

#profileテーブル
CREATE  TABLE IF NOT EXISTS `nakajima`.`web_profile` (
 `id` INT UNSIGNED NOT NULL  AUTO_INCREMENT ,
 `name` VARCHAR(255) NULL ,
 `profile` TEXT NULL ,
 `user_id` INT UNSIGNED NOT NULL ,
 PRIMARY KEY (`id`, `user_id`) ,
 INDEX `fk_profile_user` (`user_id` ASC) ,
 CONSTRAINT `fk_profile_user`
   FOREIGN KEY (`user_id` )
   REFERENCES `nakajima`.`web_user` (`id` )
   ON DELETE NO ACTION
   ON UPDATE NO ACTION)
ENGINE = InnoDB;

永続化クラス
user

package nakajima.data.dto;

import java.io.Serializable;
public class WebUser implements Serializable{

	private int id;
	private String email;
	private String password;
	private int flag;

	private WebProfile webProfile;

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

	public int getId() {
		return id;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getEmail() {
		return email;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}

	public void setFlag(int flag) {
		this.flag = flag;
	}

	public int getFlag() {
		return flag;
	}

	public void setWebProfile(WebProfile webProfile) {
		this.webProfile = webProfile;
	}

	public WebProfile getWebProfile() {
		return webProfile;
	}



}

profile

package nakajima.data.dto;
import java.io.Serializable;
public class WebProfile implements Serializable{

	private int id;
	private String name;
	private String profile;
	private int userId;

	private WebUser webUser;

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

	public int getId() {
		return id;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setProfile(String profile) {
		this.profile = profile;
	}

	public String getProfile() {
		return profile;
	}

	public void setUserId(int userId) {
		this.userId = userId;
	}

	public int getUserId() {
		return userId;
	}

	public void setWebUser(WebUser webUser) {
		this.webUser = webUser;
	}

	public WebUser getWebUser() {
		return webUser;
	}


}

マッピングファイル


<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="nakajima.data.dto.WebUser" table="web_user">
        <id name="id" column="id"  type="int" >
        	<generator class="increment" />
        </id>
        <property name="email" type="string" column="email" />
        <property name="password" type="string" column="password" />
        <property name="flag" type="int" column="flag" />
         <one-to-one name="WebProfile" class="nakajima.data.dto.WebProfile"   property-ref="WebUser" cascade="all"  />

    </class>


    <class name="nakajima.data.dto.WebProfile" table="web_profile">
    	<id name="id" column="id" type="int">
    		<generator class="increment" />
    	</id>
        <property name="name" type="string" column="name" />
        <property name="profile" type="string" column="profile" />
        <property name="userId" type="int" column="user_id" insert="false" update="false"/>
        <many-to-one name="WebUser" class="nakajima.data.dto.WebUser"  column="user_id" unique="true" />

    </class>


</hibernate-mapping>

で、テストケースがこんな感じ。

package test;

import java.util.List;

import org.hibernate.*;
import org.hibernate.cfg.Configuration;

import nakajima.data.dto.WebUser;
import nakajima.data.dto.WebProfile;

public class Test {

	public static void main(String[] args){

		Session session = connect();
		testView(session);
		testInsert(session,"test3","testpassword3");

	//	testDelete(session,5);
	//	session.flush();

	}

	public static void testDelete(Session session,int id){


		WebUser user = new WebUser();
		user.setId(id);

		Transaction trans = session.beginTransaction();
		session.delete(user);
		trans.commit();

	}


	private static Session connect(){
		Configuration config = new Configuration().configure();

		SessionFactory sessionFactory = config.buildSessionFactory();
		Session session = sessionFactory.openSession();

		return session;
	}

	public static void testView(Session session){
		List<?> list = session.createCriteria(WebUser.class).list();

		System.out.println("web_user");
		for(int i = 0; i < list.size(); i++){

			WebUser web = (WebUser)list.get(i);
			System.out.println("id:::" + web.getId() + "\t\temail:::" + web.getEmail());
			//WebProfile profile = web.getWebProfile();
			//System.out.println(profile.getName());
			System.out.println();
		}
	}

	public static void testInsert(Session session,String email,String password){
		WebUser user = new WebUser();
		user.setEmail(email);
		user.setPassword(password);
		user.setFlag(1);


		WebProfile profile = new WebProfile();
		profile.setName("ryota");
		profile.setProfile("test");
		user.setWebProfile(profile);
		profile.setWebUser(user);
		//profile.setWebUser(user);

		Transaction trans = session.beginTransaction();


		//session.save(profile);
		//user.setWebProfile(profile);
		session.save(user);
		//session.save(profile);
		//profile.setWebUser(user);
		//session.save(user);

		trans.commit();
	}

}

こんなことをしてみたら、どうしても外部キーである、web_profileテーブルのuser_idに値が入らなくてエラーになる。。。web_profileテーブルの外部参照はずして入れたところuser_idに値が入らない。。。

おわた。。。とおもってたら、どうやらAUTO_INCREMENTを設定していたのが原因で値がはいらなかったぽい。

AUTO_INCREMENT外したうまくいきましたー。
でも、AUTO_INCREMENTをを使ってうまくやる方法ないのかなぁ。。

[追記]
どうやら、AUTO_INCREMENTガ悪いわけではなく、マッピングファイルの設定が悪かったみたいです・・・。
generatorの設定が間違えていました。。。。
というかそもそもgeneratorの役割を理解していなくて・・・なんとなくサンプルに載ってから書いておくみたいな最低なことしてたため、Hibernateが動かなかったみたいです。。。

generatorは「一意キーを自動生成する方法を指定する」ってことみたいですね。
generatorのclass属性にidentityを指定すれば、AUTO_INCREMENTでも大丈夫になります。

ということで、マッピングファイルをこのように修正


<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="nakajima.data.dto.WebUser" table="web_user">
        <id name="id" column="id"  type="int" >
        	<generator class="identity" />
        </id>
        <property name="email" type="string" column="email" />
        <property name="password" type="string" column="password" />
        <property name="flag" type="int" column="flag" />
         <one-to-one name="WebProfile" class="nakajima.data.dto.WebProfile"   property-ref="WebUser" cascade="all"  />

    </class>


    <class name="nakajima.data.dto.WebProfile" table="web_profile">
    	<id name="id" column="id" type="int">
    		<generator class="identity" />
    	</id>
        <property name="name" type="string" column="name" />
        <property name="profile" type="string" column="profile" />
        <property name="userId" type="int" column="user_id" insert="false" update="false"/>
        <many-to-one name="WebUser" class="nakajima.data.dto.WebUser"  column="user_id" unique="true" />

    </class>


</hibernate-mapping>

これでAUTO_INCREMENT使った場合でもone-to-oneガ使えます。よかったよかった。

comments powered by Disqus