您的位置:首页 > 其它

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

2011-10-22 21:37 363 查看
值类型的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:

无序不允许重复:


类:

view
plaincopy
to clipboardprint?

/**

*
实现String类型的set集合,非class(实体bean)集合

*/

public class Item implements Serializable
{

private int itemId;

private String
itemName;

//不允许重复

private Set<String>
images = new HashSet<String>();

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.set">

<class name="Item">

<id
name="itemId">

<generator class="native"/>

</id>

<property
name="itemName" type="string"/>

<!--
映射了一个无序的string集合 -->

<set
name="images" table="ITEM_IMAGES">

<key
column="ITEM_ID"></key>

<element
type="string" column="FILENAME" not-null="true"></element>

</set>

</class>

</hibernate-mapping>

插入2:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().add("image1");

item.getImages().add("image1");

hibernate 打印 sql:

Hibernate: insert into Item (itemName) values (?)

Hibernate: insert into ITEM_IMAGES (ITEM_ID, FILENAME) values (?, ?)

插入2:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().add("image1");

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:

有序允许重复:


类:

view
plaincopy
to clipboardprint?

/**

*
允许重复元素的无序集合bag

*/

public class Item implements Serializable
{

private Integer
itemId;

private String
itemName;

private Collection<String>
images = new ArrayList<String>();

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.connection">

<class name="Item">

<id
name="itemId" type="integer">

<generator class="native"/>

</id>

<property
name="itemName" type="string"/>

<!--
映射了一个无序的string集合 -->

<idbag
name="images" table="ITEM_IMAGES">

<!--
给集合加一个id -->

<collection-id
type="integer" column="ITEM_IMAGE_ID">

<generator class="increment"></generator>

</collection-id>

<key
column="ITEM_ID"></key>

<element
type="string" column="FILENAME" not-null="true"></element>

</idbag>

</class>

</hibernate-mapping>

插入:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().add("image1");

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 (?, ?, ?)

注意:

view
plaincopy
to clipboardprint?

<collection-id
type="integer" column="ITEM_IMAGE_ID">

<generator class="increment"></generator>

</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集合,是不会删除子集的,只默认级联一的一端)

这里是都级联删除的

view
plaincopy
to clipboardprint?

Item
item = (Item) session.get(Item.class, 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(允许重复,有序):

view
plaincopy
to clipboardprint?

/**

*
映射list

*/

public class Item implements Serializable
{

private Integer
itemId;

private String
itemName;

private List<String>
images = new ArrayList<String>();

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.list">

<class name="Item">

<id
name="itemId" type="integer">

<generator class="native"/>

</id>

<property
name="itemName" type="string"/>

<list
name="images" table="ITEM_IMAGES">

<key
column="ITEM_ID"></key>

<!-- 2.X兼容方式,不在使用<index></index>
-->

<list-index
column="POSITION"></list-index>

<element
type="string" column="FILENAME" not-null="true"></element>

</list>

</class>

</hibernate-mapping>

插入:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().add("image1");

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...)

删除:

view
plaincopy
to clipboardprint?

Item
item = (Item) session.get(Item.class, 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(无序,不允许重复):

类:

view
plaincopy
to clipboardprint?

/**

*
映射map

*/

public class Item implements Serializable
{

private int itemId;

private String
itemName;

private Map<String,
String> images = new HashMap<String,
String>();

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.map">

<class name="Item">

<id
name="itemId">

<generator class="native"/>

</id>

<property
name="itemName" type="string"/>

<map
name="images" table="ITEM_IMAGES">

<key
column="ITEM_ID"></key>

<map-key
type="string" column="IMAGENAME"></map-key>

<element
type="string" column="FILENAME" not-null="true"/>

</map>

</class>

</hibernate-mapping>

插入:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().put("imagename1", "filename1");

item.getImages().put("imagename1", "filename1");

hibernate打印sql:

Hibernate: insert into Item (itemName) values (?)

Hibernate: insert into ITEM_IMAGES (ITEM_ID, IMAGENAME, FILENAME) values (?, ?, ?)

映射sortedmap,排序集合:

类:

view
plaincopy
to clipboardprint?

/**

*
映射sortedmap,排序集合

*/

public class Item implements Serializable
{

private int itemId;

private String
itemName;

private SortedMap<String,
String> images = new TreeMap<String,
String>();

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.sortedmap">

<class name="Item">

<id
name="itemId">

<generator class="native"/>

</id>

<property
name="itemName" type="string"/>

<!--
sort="natural"是按照string进行排序,也可实现java.util.Comparator
如:srot="cn.partner4java.MyComp" -->

<map
name="images" table="ITEM_IMAGES" sort="natural">

<key
column="ITEM_ID"></key>

<map-key
type="string" column="IMAGENAME"></map-key>

<element
type="string" column="FILENAME" not-null="true"/>

</map>

</class>

</hibernate-mapping>

插入:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().put("imagename2", "filename2");

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:

view
plaincopy
to clipboardprint?

<map
name="images" table="ITEM_IMAGES" order-by="">

<set
name="images" table="ITEM_IMAGES" order-by="FILENAME
asc">

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

组件的集合

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

<element>标签。

类:

view
plaincopy
to clipboardprint?

/**

*
映射集合

*/

public class Item implements Serializable
{

private int itemId;

private String
itemName;

private Set<ItemImage>
images = new HashSet<ItemImage>();

public class ItemImage implements Serializable
{

private String
imageName;

private String
fileName;

private int sizeX;

private int sizeY;

配置文件:

view
plaincopy
to clipboardprint?

<hibernate-mapping package="cn.partner4java.composite">

<class name="Item">

<!--
如果你不给它明确指定column="ITEM_ID",他是不会截取大写字母添加下划线的,不知道为什么,可能是现在的版本就这样了
-->

<id
name="itemId" column="ITEM_ID">

<generator class="native"/>

</id>

<property
name="itemName" type="string" column="ITEM_NAME"/>

<set
name="images" table="ITEM_IMAGE" order-by="IMAGE_NAME
asc">

<!--
是定义 ITEM_IMAGE 表,与主表关联的字段名称,和主表的id无任何关系,也就是这里可以随意写 -->

<key
column="ITEM_ID"></key>

<composite-element class="ItemImage">

<property
name="imageName" column="IMAGE_NAME" not-null="true"></property>

<property
name="fileName" column="FILE_NAME" not-null="true"></property>

<property
name="sizeX" column="SIZE_X" not-null="true"></property>

<property
name="sizeY" column="SIZE_Y" not-null="true"></property>

</composite-element>

</set>

</class>

</hibernate-mapping>

插入:

view
plaincopy
to clipboardprint?

Item
item = new Item();

item.setItemName("hello
world");

item.getImages().add(new ItemImage("imageName", "fileName", 1, 2));

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集合:

类:

view
plaincopy
to clipboardprint?

/**

*
基本的集合映射(映射无序的set集合)

*
@author partner4java

*

*/

@Entity

public class Item implements Serializable
{

@Id

@GeneratedValue

@Column(name="item_id")

private int itemId;

@Column(name="item_name",length=100)

private String
itemName;

//hibernate
annotation 包对包含值类型元素的集合映射支持非标准的注解,

//主要是CollectionOfElements

@CollectionOfElements(targetElement=java.lang.String.class)

//指定加入的表名,和加入表的对应列名

@JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))

@Column(name="FILENAME",nullable=false)

private Set<String>
images = new HashSet<String>();

有序的list集合:

view
plaincopy
to clipboardprint?

/**

*
有序的list集合

*
@author partner4java

*

*/

@Entity

public class Item implements Serializable
{

@Id

@GeneratedValue

@Column(name="ITEM_ID")

private Integer
itemId;

@Column(name="ITEM_NAME",length=100)

private String
itemName;

@CollectionOfElements(targetElement=java.lang.String.class)

@JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITME_ID"))

//为了映射持久化list,需要添加
IndexColumn,该索引列默认基数为0

@IndexColumn(name="POSITION",base=1)

@Column(name="FILENAME")

private List<String>
images = new ArrayList<String>();

映射持久化的映射Map:

view
plaincopy
to clipboardprint?

/**

*
映射持久化的映射Map

*
@author partner4java

*

*/

@Entity

public class Item implements Serializable
{

@Id

@GeneratedValue

@Column(name="ITEM_ID")

private Integer
itemId;

@Column(name="ITEM_NAME",length=100)

private String
itemName;

@CollectionOfElements

@JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))

@MapKey(columns=@Column(name="IMAGENAME"))

@Column(name="FILENAME")

private Map<String,
String> images = new HashMap<String,
String>();

排序集合:

view
plaincopy
to clipboardprint?

/**

*
排序集合

*
@author partner4java

*

*/

@Entity

public class Item implements Serializable
{

@Id

@GeneratedValue

@Column(name="ITEM_ID")

private Integer
itemId;

@Column(name="ITEM_NAME")

private String
itemName;

@CollectionOfElements

@JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))

//排序

@Sort(type=SortType.NATURAL)

@Column(name="FILENAME")

private SortedSet<String>
images = new TreeSet<String>();

添加order by排序:

view
plaincopy
to clipboardprint?

/**

*
添加order by排序

*
@author partner4java

*

*/

@Entity

public class Item implements Serializable
{

@Id

@GeneratedValue

@Column(name="ITEM_ID")

private Integer
itemId;

@Column(name="ITEM_NAME")

private String
itemName;

@CollectionOfElements(targetElement=java.lang.String.class)

@JoinTable(name="ITEM_IMAGE",joinColumns=@JoinColumn(name="ITEM_ID"))

@Column(name="FILENAME")

//对有序列号的list类型是不起作用的

@OrderBy(clause="FILENAME
asc")

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类实现:

view
plaincopy
to clipboardprint?

public class Bid{

...

private Item
item;

...

}

接下来是这个关联的Hibernate映射:

view
plaincopy
to clipboardprint?

<class

name="Bid"

table="BID">

...

<many-to-one

name="item"

column="ITEM_ID"

class="Item"

not-null="true"/>

</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标识在被维护的一端。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: