Java Persistence with Hibernate

6.Mapping collections and entity associations

java.util.Set is mapped with a <set> element. Initialize the collection

with a java.util.HashSet. The order of its elements isn’t preserved, and

duplicate elements aren’t allowed. This is the most common persistent collection

in a typical Hibernate application.(不能有重复元素,顺序不确定)

6.1.2 Mapping a set

private Set images = new HashSet();

...

public Set getImages() {

return this.images;

}

public void setImages(Set images) {

this.images = images;

}

 

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

<key column="ITEM_ID"/>

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

</set>

The <element> tag declares this collection as a collection of

value type instances—in this case, of strings.(图见pdf 279)

6.1.3 Mapping an identifier bag

private Collection images = new ArrayList();

...

public Collection getImages() {

return this.images;

}

public void setImages(Collection images) {

this.images = images;

}

 

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

<collection-id type="long" column="ITEM_IMAGE_ID">  //代理主键

<generator class="sequence"/>                        //不能为native.(idbag原因)

</collection-id>

<key column="ITEM_ID"/>

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

</idbag>

图见pdf 281.

6.1.4 Mapping a list

private List images = new ArrayList();

...

public List getImages() {

return this.images;

}

public void setImages(List images) {

this.images = images;

}

 

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

<key column="ITEM_ID"/>

<list-index column="POSITION"/>              //0开始, <list-index base="1".../>

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

</list>

 282 .

6.1.5 Mapping a map

private Map images = new HashMap();

...

public Map getImages() {

return this.images;

}

public void setImages(Map images) {

this.images = images;

}

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

<key column="ITEM_ID"/>

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

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

</map>

283,list相似.

6.1.6 Sorted and ordered collections

sorted collection is

sorted in memory using a Java comparator. An ordered collection is ordered at the

database level using an SQL query with an order by clause.(两者不同点).

 

private SortedMap images = new TreeMap();

...

public SortedMap getImages() {

return this.images;

}

public void setImages(SortedMap images) {

this.images = images;

}

 

<map name="images"

table="ITEM_IMAGE"

sort="natural">        //使用String中的compareTo()进行排序.

<key column="ITEM_ID"/>

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

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

</map>

you may specify the name of a class that implements java.util.Comparator in

the sort attribute. For example:

<map name="images"

table="ITEM_IMAGE"

sort="auction.util.comparator.ReverseStringComparator">

…….

 

A java.util.SortedSet (with a java.util.TreeSet implementation) is mapped

like this:

<set name="images"

table="ITEM_IMAGE"

sort="natural">

<key column="ITEM_ID"/>

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

</set>

使用order

<map name="images"

table="ITEM_IMAGE"

order-by="IMAGENAME asc">     //You can even includean SQL function call

in the order-by attribute: order-by="lower(FILENAME) asc"

…….

The same can be done with a set: Hibernate internally uses a LinkedHashSet.

基本的配置都相同,只是将map变换成了set. the property is a regular Set/HashSet.

还可以使用bag, Your Java collection property is either Collection/ArrayList or List/

ArrayList

其余的xml配置也与idbag一样,只是多了个order-by.

6.2 Collections of components

6.2.2 Mapping the collection

pdf 288.

<set name="images"

table="ITEM_IMAGE"

order-by="IMAGENAME asc">

<key column="ITEM_ID"/>

<composite-element class="Image">             //与上面set不同的就是这个元素取代了element.

<property name="name" column="IMAGENAME" not-null="true"/>          //这些都是image的属性.

<property name="filename" column="FILENAME" not-null="true"/>

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

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

</composite-element>

</set>

6.2.3 Enabling bidirectional navigation(双向)

add a <parent> element to the mapping:

<set name="images"                    //table与上面是一样的.

table="ITEM_IMAGE"

order-by="IMAGE_NAME asc">

<key column="ITEM_ID"/>

<composite-element class="Image">

<parent name="item"/>

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

<property name="filename" column="FILENAME" not-null="true"/>

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

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

</composite-element>

</set>

实现真正的双向是不可能的. You can’t retrieve an Image

independently and then navigate back to its parent Item

6.2.4 Avoiding not-null columns

使用collection(一般arraylist). 上面的set里面的属性都加了not-null.

<idbag name="images"

table="ITEM_IMAGE"

order-by="IMAGE_NAME asc">

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

<generator class="sequence"/>

</collection-id>

<key column="ITEM_ID"/>

<composite-element class="Image">

<property name="name" column="IMAGENAME"/>

<property name="filename" column="FILENAME" not-null="true"/>

<property name="sizeX" column="SIZEX"/>

<property name="sizeY" column="SIZEY"/> //可以存在null.

</composite-element>

</idbag>

You can remove the

name property from the Image class and use the image name as the key of a map:

<map name="images"

table="ITEM_IMAGE"

order-by="IMAGENAME asc">

<key column="ITEM_ID"/>

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

<composite-element class="Image">

<property name="filename" column="FILENAME" not-null="true"/>

<property name="sizeX" column="SIZEX"/>

<property name="sizeY" column="SIZEY"/>

</composite-element>

</map>

6.3 Mapping collections with annotations

6.3.1 Basic collection mapping

The following maps a simple collection of String elements:

@org.hibernate.annotations.CollectionOfElements(

targetElement = java.lang.String.class

)

@JoinTable(                 //合成主键,但用collection不需指名.

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

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

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

ITEM_IDFILENAME应该实在ITEM_IMAGE表里的.??

To map a persistent List, add @org.hibernate.annotations.IndexColumn

with an optional base for the index (default is zero):

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

@org.hibernate.annotations.IndexColumn(

name="POSITION", base = 1

)

@Column(name = "FILENAME")

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

To map a persistent map, use @org.hibernate.annotations.MapKey:

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

@org.hibernate.annotations.MapKey(

columns = @Column(name="IMAGENAME")

)

@Column(name = "FILENAME")

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

6.3.2 Sorted and ordered collections

A collection can also be sorted or ordered with Hibernate annotations:

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

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

@org.hibernate.annotations.Sort(

type = org.hibernate.annotations.SortType.NATURAL

)

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

If you enable SortType.COMPARATOR, you also need to set the comparator attribute

 to a class that implements your comparison routine.(即可以自己写排序规则,然后添加).

但是目前还有个疑问就是自己写的排序规则,怎么让上面这个类知道呢???

Maps, sets, and even bags, can be ordered on load, by the database, through an

SQL fragment in the ORDER BY clause:

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

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

@org.hibernate.annotations.OrderBy(

clause = "FILENAME asc"      //SQLkeyword.

)

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

6.3.3 Mapping a collection of embedded objects

You need to add the @Embeddable component annotation on that class to

enable embedding:

@Embeddable

public class Image {

@org.hibernate.annotations.Parent

Item item;        // anImage.getItem() can be useful.

@Column(length = 255, nullable = false)

private String name;

@Column(length = 255, nullable = false)

private String filename;

@Column(nullable = false)

private int sizeX;

@Column(nullable = false)

private int sizeY;

... // Constructor, accessor methods, equals()/hashCode()

}

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

@AttributeOverride(

name = "element.name",

column = @Column(name = "IMAGENAME",

length = 255,

nullable = false)

)

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

对于idbag.

@org.hibernate.annotations.CollectionOfElements

@JoinTable(

name = "ITEM_IMAGE",

joinColumns = @JoinColumn(name = "ITEM_ID")

)

@CollectionId(

columns = @Column(name = "ITEM_IMAGE_ID"),

type = @org.hibernate.annotations.Type(type = "long"),

generator = "sequence"

)

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

6.4 Mapping a parent/children relationship

说明:最近发现由于对于hibernate的认识,还处在最初级的阶段,

而且英语功底也不是很好,发现读这本书时存在比较多的疑问,

所以先暂停读一下,拿本Hibernate Annotations中文手册看下先.其实那本书

前面的也都是对API的讲解.

 

6.4.2 The simplest possible association

public class Bid {

...

private Item item;            //单向manytoOne

public void setItem(Item item) {

this.item = item;

}

public Item getItem() {

return item;

}

...

}

Next, this is the Hibernate mapping for this association:(表结构看pdf 297)

<class

name="Bid"

table="BID">

...

<many-to-one                 //多个bid对应一个item.

name="item"

column="ITEM_ID"

class="Item"

not-null="true"/>

</class>

public class Bid {

...

@ManyToOne( targetEntity = auction.model.Item.class ) //括号内可选

@JoinColumn(name = "ITEM_ID", nullable = false)

private Item item;

...

}

6.4.3 Making the association bidirectional

public class Item {         //one

...

private Set bids = new HashSet();

public void setBids(Set bids) {

this.bids = bids;

}

public Set getBids() {

return bids;

}

public void addBid(Bid bid) {

bid.setItem(this);

bids.add(bid);

}

...

}

A basic mapping for this one-to-many association looks like this:

<class

name="Item"

table="ITEM">

...

<set name="bids">

<key column="ITEM_ID"/>

<one-to-many class="Bid"/>

</set>

</class>

The inverse attribute tells Hibernate that the collection

is a mirror image of the <many-to-one> association on the other side:

set中的name后加属性inverse="true".

Let’s map this inverse collection side again, with JPA annotations:

public class Item {

...

@OneToMany(mappedBy = "item")       //mappedby相当与inverse属性.

private Set<Bid> bids = new HashSet<Bid>();

...

}

6.4.4 Cascading object state

Item newItem = new Item();

Bid newBid = new Bid();

newItem.addBid(newBid); // Set both sides of the association

session.save(newItem);

session.save(newBid);    //多余

Transitive persistence (立即持久化)

<class

name="Item"

table="ITEM">

...

<set name="bids"

inverse="true"

cascade="save-update">     //(单边的,此处对于bid来说,不保证另外一边,需要时两边都加)

                  添加一个item,同样会更新bid.

<key column="ITEM_ID"/>

<one-to-many class="Bid"/>

</set>

</class>

public class Item {

...

@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE },     //对于bid来说

mappedBy = "item")

private Set<Bid> bids = new HashSet<Bid>();

...

}

You can now simplify the code that links and saves an Item and a Bid, in native

Hibernate:

Item newItem = new Item();

Bid newBid = new Bid();

newItem.addBid(newBid); // Set both sides of the association

session.save(newItem);

With the JPA EntityManager API, the

equivalent to a Session, the code is as follows:

Item newItem = new Item();

Bid newBid = new Bid();

newItem.addBid(newBid); // Set both sides of the association

entityManager.persist(newItem); //只是换成了entityManager

下面是关于cascadeinverse的区别

What is the effect of cascade on inverseMany new Hibernate users ask

this question. The answer is simple: The cascade attribute has nothing to

do with the inverse attribute. They often appear on the same collection

mapping. If you map a collection of entities as inverse="true", you’re

controlling the generation of SQL for a bidirectional association mapping.

It’s a hint that tells Hibernate you mapped the same foreign key

column twice. On the other hand, cascading is used as a convenience feature.

If you decide to cascade operations from one side of an entity relationship

to associated entities, you save the lines of code needed to

manage the state of the other side manually. We say that object state

becomes transitive. You can cascade state not only on collections of entities,

but on all entity association mappings. cascade and inverse have in

common the fact that they don’t appear on collections of value types or

on any other value-type mappings. The rules for these are implied by the

nature of value types.

根据上面,我目前的理解inverse是告诉hibernate,对于一个外键,在程序中我关联

了两次,对于cascade就是持久化的问题了,cascade不仅仅是collection,还可以是

任意有关联的属性.

Cascading deletion

Item anItem = // Load an item

// Delete all the referenced bids

for ( Iterator<Bid> it = anItem.getBids().iterator();     //这里一个个移除bid,有点多余.

it.hasNext(); ) {

Bid bid = it.next();

it.remove(); // Remove reference from collection

session.delete(bid); // Delete it from the database

}

session.delete(anItem); // Finally, delete the item

Hibernate (and JPA) offer a cascading option for this purpose. You can enable

cascading for the delete operation:

<set name="bids"

inverse="true"

cascade="save-update, delete">

...

The operation you cascade in JPA is called remove:

public class Item {

...

@OneToMany(cascade = { CascadeType.PERSIST,

CascadeType.MERGE,

CascadeType.REMOVE },

mappedBy = "item")

private Set<Bid> bids = new HashSet<Bid>();

...

}

The same code to delete an item and all its bids is reduced to the following, in

Hibernate or with JPA:

Item anItem = // Load an item

session.delete(anItem);     //现在就不需要上面那样一个个移除.

entityManager.remove(anItem);

如果还闲扯到User,UserBid也有关系,上面就不能这样删除了,会有异常.

先要找到那些与bid有关的User,再在userbid的关系里一次删除bid.最后才能

正常删除这个item.

Item anItem = // Load an item

// Delete all the referenced bids

for ( Iterator<Bid> it = anItem.getBids().iterator();

it.hasNext(); ) {

Bid bid = it.next();

// Remove references from users who have made this bid

Query q = session.createQuery(

"from User u where :bid in elements(u.bids)"

);

q.setParameter("bid", bid);

Collection usersWithThisBid = q.list();

for (Iterator itUsers = usersWithThisBid.iterator();

itUsers.hasNext();) {

User user = (User) itUsers.next();

user.getBids().remove(bid);

}

}

session.delete(anItem);

// Finally, delete the item and the associated bids

if you don’t have shared references to an entity, you

should rethink your mapping and map the bids as a collection components (with

the Bid as a <composite-element>). With an <idbag> mapping, even the tables

look the same:(利用idbag解决)

<class

name="Item"

table="ITEM">

...

<idbag name="bids" table="BID">

<collection-id type="long" column="BID_ID">

<generator class="sequence"/>

</collection-id>

<key column="ITEM_ID" not-null="true"/>

<composite-element class="Bid">

<parent name="item"/>

<property .../>

...

</composite-element>

</idbag>

</class>

Enabling orphan deletion

all-delete-orphan,在多端进行删除操作时,会再多端表中留下null空纪录,

设置了级联操作为delete之会将表中表示关联的外键id置成null,不会将这条

纪录也删除掉,而把级联设置成delete-orphan就不会留有空纪录,而是级联

的把相关纪录删除掉。

This option is called cascade orphan delete. You can enable it on a collection

mapping in XML as follows:

<set name="bids"

inverse="true"

cascade="save-update, delete, delete-orphan">

...

With annotations, this feature is available only as a Hibernate extension:

public class Item {

...

@OneToMany(cascade = { CascadeType.PERSIST,

CascadeType.MERGE,

CascadeType.REMOVE },

mappedBy = "item")

@org.hibernate.annotations.Cascade(

value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN

)

private Set<Bid> bids = new HashSet<Bid>();

...

}

Finally, let’s look at the mapping in a JPA XML descriptor:

<entity-mappings>

<entity class="auction.model.Item" access="FIELD">

...

<one-to-many name="bids" mapped-by="item">

<cascade>

<cascade-persist/>

<cascade-merge/>

<cascade-remove/>

</cascade>

</one-to-many>

</entity>

<entity class="auction.model.Bid" access="FIELD">

...

<many-to-one name="item">

<join-column name="ITEM_ID"/>

</many-to-one>

</entity>

</entity-mappings>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值