hibernate 6 映射集合和实体关联 | hibernate 实战(第二版) 第6章映射集合和实体关联 | 笔记

值类型的set、bag、list和map 
选择集合接口: 
1、使用<Set>元素映射java.util.Set。使用java.util.HashSet初始化集合。它是无序且不允许重复。 
2、使用<Set>映射java.util.SortedSet。且sort属性可以设置成比较器或者用于内存的排序的自然顺序。使用 
java.util.TreeSet实例初始化集合。 
3、使用<list>映射java.util.List。在集合表中用一个额外的索引列保存每个元素的位置。使用java.util.ArrayList初始化。 
4、使用<bag>或者<idbag>映射java.util.Collection。java没有Bag接口或者实现;然而,java.util.Collection允许包 
语义。hibernate支持持久化的包。使用java.util.ArrayList初始化包集合。 
5、使用<map>映射java.util.Map,保存键和值对。使用java.util.HashMap初始化属性。 
6、使用<map>映射java.util.SortedMap。且sort属性可以设置为比较器或者用于内存排序的自然顺序。使用 
java.util.TreeMap实例初始化该集合。 
7、hibernate使用<primitve-array>和<array>支持数组。但是他们很少使用在领域模型中。因为hibernate无法 
包装数组属性,没有字节码基础设施(BCI),就失去了延迟加载,以及持久化集合优化过的脏检查、基本 
的便利和性能特性。 





映射Set: 

无序不允许重复:
 
类: 
  1. /** 
  2. * 实现String类型的set集合,非class(实体bean)集合 
  3. */  
  4. public class Item implements Serializable {  
  5.     private int itemId;  
  6.     private String itemName;  
  7.       
  8.     //不允许重复  
  9.     private Set<String> images = new HashSet<String>();  

配置文件: 
  1. <hibernate-mapping package="cn.partner4java.set">  
  2.   
  3.     <class name="Item">  
  4.         <id name="itemId">  
  5.             <generator class="native"/>  
  6.         </id>  
  7.         <property name="itemName" type="string"/>  
  8.         <!-- 映射了一个无序的string集合 -->  
  9.         <set name="images" table="ITEM_IMAGES">  
  10.             <key column="ITEM_ID"></key>  
  11.             <element type="string" column="FILENAME" not-null="true"></element>  
  12.         </set>  
  13.           
  14.     </class>  
  15.   
  16. </hibernate-mapping>  

插入2: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().add("image1");  
  4. item.getImages().add("image1");  

hibernate 打印 sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, FILENAME) values (?, ?) 
插入2: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().add("image1");  
  4. item.getImages().add("image2");  

hibernate打印sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, FILENAME) values (?, ?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, FILENAME) values (?, ?)





映射bag: 
有序允许重复:
 
类: 
  1. /** 
  2. * 允许重复元素的无序集合bag 
  3. */  
  4. public class Item implements Serializable {  
  5.     private Integer itemId;  
  6.     private String itemName;  
  7.     private Collection<String> images = new ArrayList<String>();  

配置文件:
  1. <hibernate-mapping package="cn.partner4java.connection">  
  2.   
  3.     <class name="Item">  
  4.         <id name="itemId" type="integer">  
  5.             <generator class="native"/>  
  6.         </id>  
  7.         <property name="itemName" type="string"/>  
  8.         <!-- 映射了一个无序的string集合 -->  
  9.         <idbag name="images" table="ITEM_IMAGES">  
  10.             <!-- 给集合加一个id -->  
  11.             <collection-id type="integer" column="ITEM_IMAGE_ID">  
  12.                 <generator class="increment"></generator>  
  13.             </collection-id>  
  14.               
  15.             <key column="ITEM_ID"></key>  
  16.             <element type="string" column="FILENAME" not-null="true"></element>  
  17.         </idbag>  
  18.           
  19.     </class>  
  20.   
  21. </hibernate-mapping>  

插入: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().add("image1");  
  4. item.getImages().add("image1");  

hibernate打印sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: select max(ITEM_IMAGE_ID) from ITEM_IMAGES 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, ITEM_IMAGE_ID, FILENAME) values (?, ?, ?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, ITEM_IMAGE_ID, FILENAME) values (?, ?, ?) 
注意: 
  1. <collection-id type="integer" column="ITEM_IMAGE_ID">  
  2.     <generator class="increment"></generator>  
  3. </collection-id>  

这里的generator给的类型是increment,如果mysql给的是native或者identity会报错: 
org.hibernate.id.IdentifierGeneratorFactory$2 cannot be cast to java.lang.Integer 
但是oracle使用native、sequence不会报错(应该是这个版本的hibernate的bug) 

**删除**: 
(如果没记错的话,类类型的set集合,是不会删除子集的,只默认级联一的一端) 
这里是都级联删除的 
  1. Item item = (Item) session.get(Item.class2);  
  2. session.delete(item);     

Hibernate: select item0_.itemId as itemId0_0_, item0_.itemName as itemName0_0_ from Item item0_ where item0_.itemId=? 
Hibernate: delete from ITEM_IMAGES where ITEM_ID=? 
Hibernate: delete from Item where itemId=? 



映射list(允许重复,有序): 
  1. /** 
  2. * 映射list 
  3. */  
  4. public class Item implements Serializable {  
  5.     private Integer itemId;  
  6.     private String itemName;  
  7.     private List<String> images = new ArrayList<String>();  

配置文件:
  1. <hibernate-mapping package="cn.partner4java.list">  
  2.     <class name="Item">  
  3.         <id name="itemId" type="integer">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="itemName" type="string"/>  
  7.         <list name="images" table="ITEM_IMAGES">  
  8.             <key column="ITEM_ID"></key>  
  9.             <!-- 2.X兼容方式,不在使用<index></index> -->  
  10.             <list-index column="POSITION"></list-index>  
  11.             <element type="string" column="FILENAME" not-null="true"></element>  
  12.         </list>  
  13.     </class>  
  14. </hibernate-mapping>    

插入: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().add("image1");  
  4. item.getImages().add("image1");  

hibernate打印sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, POSITION, FILENAME) values (?, ?, ?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, POSITION, FILENAME) values (?, ?, ?)
(POSITION记录的就是list的指针位置0、1、2...) 
删除: 
  1. Item item = (Item) session.get(Item.class2);  
  2. session.delete(item);  

Hibernate: select item0_.itemId as itemId0_0_, item0_.itemName as itemName0_0_ from Item item0_ where item0_.itemId=? 
Hibernate: delete from ITEM_IMAGES where ITEM_ID=? 
Hibernate: delete from Item where itemId=?



映射map(无序,不允许重复): 
类: 
  1. /** 
  2. * 映射map 
  3. */  
  4. public class Item implements Serializable {  
  5.     private int itemId;  
  6.     private String itemName;  
  7.       
  8.     private Map<String, String> images = new HashMap<String, String>();  

配置文件: 
  1. <hibernate-mapping package="cn.partner4java.map">  
  2.     <class name="Item">  
  3.         <id name="itemId">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="itemName" type="string"/>  
  7.         <map name="images" table="ITEM_IMAGES">  
  8.             <key column="ITEM_ID"></key>  
  9.             <map-key type="string" column="IMAGENAME"></map-key>  
  10.             <element type="string" column="FILENAME" not-null="true"/>  
  11.         </map>      
  12.     </class>  
  13. </hibernate-mapping>  

插入: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().put("imagename1""filename1");  
  4. item.getImages().put("imagename1""filename1");  

hibernate打印sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, IMAGENAME, FILENAME) values (?, ?, ?) 




映射sortedmap,排序集合: 
类: 
  1. /** 
  2. * 映射sortedmap,排序集合 
  3. */  
  4. public class Item implements Serializable {  
  5.     private int itemId;  
  6.     private String itemName;  
  7.       
  8.     private SortedMap<String, String> images = new TreeMap<String, String>();  

配置文件: 
  1. <hibernate-mapping package="cn.partner4java.sortedmap">  
  2.     <class name="Item">  
  3.         <id name="itemId">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="itemName" type="string"/>  
  7.         <!-- sort="natural"是按照string进行排序,也可实现java.util.Comparator 如:srot="cn.partner4java.MyComp" -->  
  8.         <map name="images" table="ITEM_IMAGES" sort="natural">  
  9.             <key column="ITEM_ID"></key>  
  10.             <map-key type="string" column="IMAGENAME"></map-key>  
  11.             <element type="string" column="FILENAME" not-null="true"/>  
  12.         </map>      
  13.     </class>  
  14. </hibernate-mapping>  

插入: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3. item.getImages().put("imagename2""filename2");  
  4. item.getImages().put("imagename1""filename1");  

hibernate打印sql: 
Hibernate: insert into Item (itemName) values (?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, IMAGENAME, FILENAME) values (?, ?, ?) 
Hibernate: insert into ITEM_IMAGES (ITEM_ID, IMAGENAME, FILENAME) values (?, ?, ?) 
(数据中,images1的插入顺序是按照string排序的,也就是先插入了imagename1)


order-by: 
  1. <map name="images" table="ITEM_IMAGES" order-by="">  
  2. <set name="images" table="ITEM_IMAGES" order-by="FILENAME asc">  

order-by属性中的表达式是SQL order by 子句的一个片段,可以按集合表的任何列进行排序。 



组件的集合 

组件的集合被类似地映射到JDK值类型的集合。唯一的区别是用<composite-element>代替 
<element>标签。 

类: 
  1. /** 
  2. * 映射集合 
  3. */  
  4. public class Item implements Serializable {  
  5.     private int itemId;  
  6.     private String itemName;  
  7.       
  8.     private Set<ItemImage> images = new HashSet<ItemImage>();  
  9.       
  10.   
  11. public class ItemImage implements Serializable {  
  12.     private String imageName;  
  13.     private String fileName;  
  14.     private int sizeX;  
  15.     private int sizeY;  
  16.       

配置文件: 
  1. <hibernate-mapping package="cn.partner4java.composite">  
  2.   
  3.     <class name="Item">  
  4.         <!-- 如果你不给它明确指定column="ITEM_ID",他是不会截取大写字母添加下划线的,不知道为什么,可能是现在的版本就这样了 -->  
  5.         <id name="itemId" column="ITEM_ID">  
  6.             <generator class="native"/>  
  7.         </id>  
  8.         <property name="itemName" type="string" column="ITEM_NAME"/>  
  9.           
  10.         <set name="images" table="ITEM_IMAGE" order-by="IMAGE_NAME asc">  
  11.             <!-- 是定义 ITEM_IMAGE 表,与主表关联的字段名称,和主表的id无任何关系,也就是这里可以随意写 -->  
  12.             <key column="ITEM_ID"></key>  
  13.             <composite-element class="ItemImage">  
  14.                 <property name="imageName" column="IMAGE_NAME" not-null="true"></property>  
  15.                 <property name="fileName" column="FILE_NAME" not-null="true"></property>  
  16.                 <property name="sizeX" column="SIZE_X" not-null="true"></property>  
  17.                 <property name="sizeY" column="SIZE_Y" not-null="true"></property>  
  18.             </composite-element>  
  19.         </set>          
  20.     </class>  
  21.   
  22. </hibernate-mapping>  

插入: 
  1. Item item = new Item();  
  2. item.setItemName("hello world");  
  3.   
  4. item.getImages().add(new ItemImage("imageName""fileName"12));   

hibernate打印sql: 
Hibernate: insert into Item (ITEM_NAME) values (?) 
Hibernate: insert into ITEM_IMAGE (ITEM_ID, IMAGE_NAME, FILE_NAME, SIZE_X, SIZE_Y) values (?, ?, ?, ?, ?) 



用注解映射集合 
基本的集合映射: 

映射无序的set集合: 
类: 
  1. /** 
  2. * 基本的集合映射(映射无序的set集合) 
  3. * @author partner4java 
  4. * 
  5. */  
  6. @Entity  
  7. public class Item implements Serializable {  
  8.     @Id  
  9.     @GeneratedValue  
  10.     @Column(name="item_id")  
  11.     private int itemId;  
  12.       
  13.     @Column(name="item_name",length=100)  
  14.     private String itemName;  
  15.       
  16.     //hibernate annotation 包对包含值类型元素的集合映射支持非标准的注解,  
  17.     //主要是CollectionOfElements  
  18.     @CollectionOfElements(targetElement=java.lang.String.class)  
  19.     //指定加入的表名,和加入表的对应列名  
  20.     @JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))  
  21.     @Column(name="FILENAME",nullable=false)  
  22.     private Set<String> images = new HashSet<String>();  



有序的list集合: 
  1. /** 
  2. * 有序的list集合 
  3. * @author partner4java 
  4. * 
  5. */  
  6. @Entity  
  7. public class Item implements Serializable {  
  8.     @Id  
  9.     @GeneratedValue  
  10.     @Column(name="ITEM_ID")  
  11.     private Integer itemId;  
  12.       
  13.     @Column(name="ITEM_NAME",length=100)  
  14.     private String itemName;  
  15.       
  16.     @CollectionOfElements(targetElement=java.lang.String.class)  
  17.     @JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITME_ID"))  
  18.     //为了映射持久化list,需要添加 IndexColumn,该索引列默认基数为0  
  19.     @IndexColumn(name="POSITION",base=1)  
  20.     @Column(name="FILENAME")  
  21.     private List<String> images = new ArrayList<String>();    
  22.       


映射持久化的映射Map: 
  1. /** 
  2. * 映射持久化的映射Map 
  3. * @author partner4java 
  4. * 
  5. */  
  6. @Entity  
  7. public class Item implements Serializable {  
  8.     @Id  
  9.     @GeneratedValue  
  10.     @Column(name="ITEM_ID")  
  11.     private Integer itemId;  
  12.       
  13.     @Column(name="ITEM_NAME",length=100)  
  14.     private String itemName;  
  15.       
  16.     @CollectionOfElements  
  17.     @JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))  
  18.     @MapKey(columns=@Column(name="IMAGENAME"))  
  19.     @Column(name="FILENAME")  
  20.     private Map<String, String> images = new HashMap<String, String>();   
  21.       




排序集合: 
  1. /** 
  2. * 排序集合 
  3. * @author partner4java 
  4. * 
  5. */  
  6. @Entity  
  7. public class Item implements Serializable {  
  8.     @Id  
  9.     @GeneratedValue  
  10.     @Column(name="ITEM_ID")  
  11.     private Integer itemId;  
  12.       
  13.     @Column(name="ITEM_NAME")  
  14.     private String itemName;  
  15.       
  16.     @CollectionOfElements  
  17.     @JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))  
  18.     //排序  
  19.     @Sort(type=SortType.NATURAL)  
  20.     @Column(name="FILENAME")  
  21.     private SortedSet<String> images = new TreeSet<String>();     
  22.       



添加order by排序: 
  1. /** 
  2. * 添加order by排序 
  3. * @author partner4java 
  4. * 
  5. */  
  6. @Entity  
  7. public class Item implements Serializable {  
  8.     @Id  
  9.     @GeneratedValue  
  10.     @Column(name="ITEM_ID")  
  11.     private Integer itemId;  
  12.       
  13.     @Column(name="ITEM_NAME")  
  14.     private String itemName;  
  15.       
  16.     @CollectionOfElements(targetElement=java.lang.String.class)  
  17.     @JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))  
  18.     @Column(name="FILENAME")  
  19.     //对有序列号的list类型是不起作用的  
  20.     @OrderBy(clause="FILENAME asc")  
  21.     private Set<String> images = new HashSet<String>();   





映射父子关系
许多开发人员在开始使用hibernate时要尝试的第一件事就是父子关系的映射。 
这通常是你第一次遇到集合,也是你第一次必须思考实体和值类型之间的区别, 
否则会在ORM的复杂性中迷失。 


下面简要的阐述了关系映射: 


多样性: 
在描述和分类关联时,我们通常使用术语多样性。在我们的例子中,多样性只是两小块信息: 
一个特定的Item可以有不止一个Bid吗? 
一个特定的Bid可以有不止一个Item吗? 

看一眼领域模型之后,就可以推断:从Bid到Item的关联是一个多对一的关联。回忆一下,关联是有方向性的, 
把从Item到Bid的方向关联归为一对多的关联。 
另外只有两种可能:多对多和一对一。 
在对象持久化的上下文中,我们不关注多个(many)是否意味着两个或者最大五个或者没有限制:只关注大多数 
关联的选择性;不特别关心是否需要关联的实例,或者关联的另一侧是否可以为空。但是,这些是影响你在关系 
数据库Schema中选择完整性规则和在SQL DDL中定义约束的重要方面。 




最简单的可能关联: 
从Bid到Item的关联(反之亦然)是一种最简单的可能实体关联的例子。两个类中有两个属性。一个是引用的集合,另一个是单个引用。 
首先,这是Bid的Java类实现: 
  1. public class Bid{  
  2.     ...  
  3.     private Item item;  
  4.     ...  
  5. }  

接下来是这个关联的Hibernate映射: 
  1. <class  
  2.     name="Bid"  
  3.     table="BID">  
  4.     ...  
  5.     <many-to-one  
  6.         name="item"  
  7.         column="ITEM_ID"  
  8.         class="Item"  
  9.         not-null="true"/>  
  10. </class>    

如果拿这个与本章前面的集合映射进行比较,会发现你用一个不同的元素<one-to-many>映射了集合内容。这表明集合没有包含值类型实例, 
而是包含了对实体实例的引用。现在hibernate知道如何处理共享的引用和被关联对象的生命周期(他禁用了值类型实例的所有隐式依赖的 
生命周期)。hibernate也知道用给集合的表语目标实体类被映射到的表相同--<set>映射不需要table属性。 
由<key>元素定义的列映射的BID表的外键列ITEM_ID,即已经在关系的另一侧映射的同一个列。 
注意,表Schema并没有改变:它与之前你的映射关联的多彻一样。但是,有一点不同:not null="true"不见了。问题是现在有两个不同的单项 
关联映射到同一个外键列。 


哪一侧控制这个列呢? 
在运行时,同一个外键值有两个不同的内存表示法:Bid的item属性和由Item保存的bids集合的一个元素。假设应用程序修改了关联,例如通过 
在addBid()方法的这个片段中对货品添加出价: 
bid.setItem(item); 
bids.add(bid); 
在这种情况下hibernate侦测到内存持久化实例的两处变化。从数据库的观点来看,只有一个值必须更新以体现这些变化:BID表的ITEM_ID列。 
hibernate没有透明地侦测到引用同一个数据库列的两处变化,因为此时还没有做任何事来表明这是一个双向的关联。换句话说,已经映射了 
同一个列两次,hibernate始终需要知道这一点,因为它无法自动侦测到这个重复。 
在关联映射中还需要做一件事情,就是是他成为真正的双向关联映射。inverse属性告诉hibernate,集合是<many-to-one>关联在另一侧的一个镜像: 
也就是inverse一侧的改变不会引起数据库的改变,另一侧的改变才会引起数据库的改变。也就是把inverse标识在被维护的一端。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值