http://jinnianshilongnian.iteye.com/blog/1522591
单向
定义:不知道另一端什么情况,获取一端另一端自动获取,因为单向,你不知道另一侧是什么。
如 class A{ B b;}
class B{ }
只能从A导航到B,不能从B导航到A
关系维护:另一端维护,如B维护
双向
定义:知道另一端(两个单向),从一端获取另一端,从另一端也能获取一端
如 class A{ B b;}
class B{ A a;}
只能从A导航到B,也能从B导航到A
关系维护:两端,对关联的一侧所作的改变,会立即影响到另一侧
关联的多样性:
从一侧看是多对一,从另一侧看是一对多
另外还有一对一、多对多
EJB CMP:天生双向,对关联的一侧所作的改变,会立即影响到另一侧,
如userGeneral.set(user),则自动调用user.setUserGeneral(userGeneral)
Hibernate、JPA:天生单向,两侧关系的维护是不同的关联,必须手工维护
如userGeneral.set(user),则需要手工调用user.setUserGeneral(userGeneral)。
5.2.2.3、一对一主键关系映射(非延迟抓取)
配置1(UserModel.hbm.xml)
- <one-to-one name="userGeneral" cascade="all"/>
配置2(UserGeneralModel.hbm.xml)
- <id name="uuid">
- <generator class="foreign">
- <param name="property">user</param>
- </generator>
- </id>
- <one-to-one name="user"
- class="cn.javass.h3test.model.UserModel"/>
关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- session.save(user);
- //若没有cascade="all",这句必须
- //session.save(userGeneral);
1、一对一必须手工维护双向关系。
2、cascade="all":表示保存user时自动保存userGeneral,否则还需要一条save(userGeneral)
3、constrained:添加把userGeneral表的主键映射到user主键的外键约束
5.2.2.4、一对多关系映射(父/子关系映射)
配置1(UserModel.hbm.xml)
- <set name="farms" cascade="all">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.FarmModel"/>
- </set>
配置2(FarmModel.hbm.xml)
- <many-to-one name="user" column="fk_user_id"
- class="cn.javass.h3test.model.UserModel">
测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- FarmModel farm = new FarmModel();
- farm.setName("farm1");
- farm.setUser(user);
- user.getFarms().add(farm);
- //session.save(farm);//若没有cascade=all的话需要这条语句
- session.save(user);
以上配置有问题:
- insert into TBL_USER (name, age, province, city, street, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_USER_GENERAL (realname, gender, birthday, weight, height, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_FARM (name, fk_user_id, uuid) values (?, ?, ?)
- update TBL_FARM set fk_user_id=? where uuid=?
1、持久化user(UserModel);
2、持久化user的一对一关系,即userGeneral(UserGeneralModel);
3、持久化user的一对多关系,即farms(Set<FarmModel>);
3.1、首先发现farm是TO,级联save;(因为在这可能是PO,PO的话就应该update,而不是save);
3.2、其次发现farm在farms集合中,因此需要更新外键(fk_user_id),即执行“update TBL_FARM set fk_user_id=? where uuid=? “。
解决这个问题:
告诉Hibernate应该只有一端来维护关系(外键),另一端不维护;通过指定<set>端的inverse=”true”,表示关系应该由farm端维护。即更新外键(fk_user_id)将由farm端维护。
配置修改(UserModel.hbm.xml)
- <set name="farms" cascade="all" inverse="true">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.FarmModel"/>
- </set>
再测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- FarmModel farm = new FarmModel();
- farm.setName("farm1");
- farm.setUser(user);
- user.getFarms().add(farm);
- //session.save(farm);//若没有cascade=all的话需要这条语句
- session.save(user);
更新外键,需要修改FarmModel的外键并update:
- insert into TBL_USER (name, age, province, city, street, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_USER_GENERAL (realname, gender, birthday, weight, height, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_FARM (name, fk_user_id, uuid) values (?, ?, ?)
级联删除
1、当删除user时自动删除user下的farm
- user = (UserModel) session.get(UserModel.class, 1);
- session.delete(user);
结果:
- Hibernate: delete from TBL_USER_GENERAL where uuid=?
- Hibernate: delete from TBL_FARM where uuid=?
- Hibernate: delete from TBL_USER where uuid=?
2、删除user中的farms的一个元素
- UserModel user =
- (UserModel) session.get(UserModel.class, 118);
- FarmModel farm = (FarmModel) user.getFarms().toArray()[user.getFarms().size() - 1];
- user.getFarms().remove(farm);//1.必须先从集合删除
- session.delete(farm);//2.然后才能删除
结果:
- Hibernate: delete from TBL_FARM where uuid=?
如果将子对象从集合中移除,实际上我们是想删除它。要实现这种要求,就必须使用cascade="all-delete-orphan"
。无需再调用session.delete(farm)
5.2.2.5、多对多关系映射:不用
为什么不使用多对多:当添加新字段时给谁?
那实际项目如何用:拆成两个一对多。