您的位置:首页 > 其它

<二>重温Hibernate one to one 映射

2015-07-08 16:18 357 查看
用户表:

CREATE TABLE `tbl_user`

(`id` INT(32) NOT NULL AUTO_INCREMENT,`user_name` VARCHAR(20) NULL DEFAULT NULL,

`password` VARCHAR(20) NULL DEFAULT NULL,PRIMARY KEY (`id`)

)

用户会员表:

CREATE TABLE `tbl_member`

(`id` INT(10) NOT NULL AUTO_INCREMENT,`card_no` VARCHAR(50) NULL DEFAULT NULL,

`user_id` INT(11) NULL DEFAULT NULL,PRIMARY KEY (`id`),

INDEX `FK_tbl_member_tbl_user` (`user_id`),

CONSTRAINT `FK_tbl_member_tbl_user` FOREIGN KEY (`user_id`) REFERENCES `tbl_user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE

)

一对一关联分为主键关联与外键关联。

主键关联:不必加额外的字段,只是主表和辅表的主键相关联,即这两个主键的值是一样的。

外键关联:辅表有一个额外的字段和主表相关联,或者两个表都有额外的字段与对应表的相关联。

public class Users {

private int id;

private String userName;

private String password;

private Account account;

//getter and setter

}

public class Account {

private int id;

private String cardNo;

private Users users;

//getter and setter

}

Main方法:

Session session=null;

Transaction tran=null;

try {

session=HibernateSessionFactory.getSession();

tran=session.beginTransaction();

Users users=new Users();

users.setUserName("zhangsan");

users.setPassword("123456");

Member member=new Member();

member.setCardNo("002568853369_lisi");

member.setUsers(users);

session.save(member);

tran.commit();

} catch (HibernateException e) {

tran.rollback();

e.printStackTrace();

}finally{

session.flush();

session.close();

}

1.单方外键关联

这种关联member是用many-to-one然后用unique="true"做限制,限制成一对一的关系。所以,一对一的外键关联其实就是多对一关联的一种特例。

Member xml

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetoone.bean.Member" table="tbl_member">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="cardNo" type="java.lang.String" column="card_no"/>

<many-to-one name="users" column="user_id" unique="true" cascade="all"></many-to-one>

</class>

</hibernate-mapping>

User xml

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetoone.bean.Users" table="tbl_user">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="userName" type="java.lang.String" column="user_name"/>

<property name="password" type="java.lang.String" column="password"/>

<!--

property-ref属性为user,property-ref:表明从Users(users属性)建立了从Users(member属性)对象到Member对象的关联,

只要调用user持久化对象的getMember()方法,就能导航到member对象,

-->

<one-to-one name="member" class="wb.wk.review.mapping.onetoone.bean.Member"

property-ref="users" cascade="all">

</one-to-one>

</class>

</hibernate-mapping>

运行main方法:

出现异常org.hibernate.MappingException: Unknown entity: wb.wk.review.mapping.onetoone.byForeignKey.Member

原因:hibernate.cfg.xml忘记导入相应的xml

再次运行,出现异常:

Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (`ppi`.`tbl_member`, CONSTRAINT `FK_tbl_member_tbl_user` FOREIGN KEY (`user_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

原因是在id属性里必须设置generator 主键生成策略属性,我当时设置了assigned结果出现此异常。

注意:我使用的mysql,所以设置成”identity”,不同的数据库要设置不同的属性类别。具体的参照转载的一篇文章:http://blog.csdn.net/u013803303/article/details/46813249

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

最后运行成功,双表均插入成功。

总结:member表的外键use_id和user表的主键id对应,这没啥好说的。

2.主键关联

user xml

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetoone.bean.Users" table="tbl_user">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="userName" type="java.lang.String" column="user_name"/>

<property name="password" type="java.lang.String" column="password"/>

<one-to-one name="member" class="wb.wk.review.mapping.onetoone.bean.Member" cascade="all" >

</one-to-one>

</class>

</hibernate-mapping>

Member xml:

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetoone.bean.Member" table="tbl_member">

<id name="id" column="id">

<generator class="foreign">

<param name="property">users</param>

</generator>

</id>

<property name="cardNo" type="java.lang.String" column="card_no"/>

<one-to-one name="users" class="wb.wk.review.mapping.onetoone.bean.Users" constrained="true">

</one-to-one>

<!-- constrained属性为true,代表user表的主键id同时作为外键,id必须为foreign生成策略 -->

</class>

</hibernate-mapping>

运行后出现下面异常:

org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update

.......

Caused by: java.sql.BatchUpdateException: Field 'user_id' doesn't have a default value

发现是数据库没有设置自动增长。设置好运行,又出现:

org.hibernate.PropertyValueException: not-null property references a null or transient value: wb.wk.review.mapping.onetoone.bean.Users.member.

调试后发现是因为外检表(member表)的constrained属性忘记设置了。不设置此属性,member表的外键就为null,出现此异常

再次运行成功。

总结:插入后查询数据库发现,member表的id和user表的id是一一对应的,这应该就能很好的解释了什么是主键关联。但是member表外键user_id为null,由此看来主键关联适用于没有外键关联的,双表关联。

3. 双方外键关联

如果关联双方都是外键关联,那可以两边都用many-to-one。

<many-to-one name="member" cascade="all" unique="true"

column="member_id" />

Account配置(类不变)

<many-to-one name="user" unique="true" column="user_id"

cascade="all" />

这个就不写测试了。

最后网上找了个官方的配置介绍:

<one-to-one name="propertyName" (1) class="ClassName" (2)cascade="cascade_style"(3) constrained="true|false"(4)fetch="join|select" (5)property-ref="propertyNameFromAssociatedClass" (6)access="field|property|ClassName" (7)formula="anySQLexpression" (8)

lazy="proxy|no-proxy|false" (9) entity-name="EntityName"(10)

node="element-name|@attribute-name|element/@attribute|."

mbed-xml="true|false"foreign-key="foreign_key_name"/>

(1) name: 属性的名字。

(2) class (可选 - 默认是通过反射得到的属性类型):被关联的类的名字。

(3) cascade(级联) (可选):表明操作是否从父对象级联到被关联的对象。

(4) constrained(约束) (可选):表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。 这个选项影响save()和delete()在级联执行时的先后顺序以及 决定该关联能否被委托(也在schema export tool中被使用).

(5) fetch (可选 - 默认设置为选择): 在外连接抓取或者序列选择抓取选择其一.

(6) property-ref (可选):指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键。

(7) access (可选 - 默认是 property): Hibernate用来访问属性的策略。

(8) formula (可选):绝大多数一对一的关联都指向其实体的主键。在一些少见的情况中, 你可能会指向其他的一个或多个字段,或者是一个表达式,这些情况下,你可以用一个SQL公式来表示。 (可以在org.hibernate.test.onetooneformula找到例子)

(9) lazy (可选 - 默认为 proxy): 默认情况下,单点关联是经过代理的。lazy="no-proxy"指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。 lazy="false"指定此关联总是被预先抓取。注意,如果constrained="false", 不可能使用代理,Hibernate会采取预先抓取!

(10) entity-name (可选): 被关联的类的实体名。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: