- 论坛徽章:
- 0
|
6.Mapping collections and entity associations
A java.util.Set is mapped with a 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;
}
element type="string" column="FILENAME" not-null="true"/>
The 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"> //代理主键
//不能为native.(idbag原因)
element type="string" column="FILENAME" not-null="true"/>
图见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-index column="POSITION"/> //从0开始,
图 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-key column="IMAGENAME" type="string"/>
element type="string" column="FILENAME" not-null="true"/>
图283,与list相似.
6.1.6 Sorted and ordered collections
A 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;
}
table="ITEM_IMAGE"
sort="natural"> //使用String中的compareTo()进行排序.
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">
使用order
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页.
table="ITEM_IMAGE"
order-by="IMAGENAME asc">
composite-element class="Image"> //与上面set不同的就是这个元素取代了element.
property name="name" column="IMAGENAME" not-null="true"/> //这些都是image的属性.
6.2.3 Enabling bidirectional navigation(双向)
add a element to the mapping:
//table与上面是一样的.
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
parent name="item"/>
实现真正的双向是不可能的. 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">
//可以存在null值.
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">
map-key type="string" column="IMAGENAME"/>
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 images = new HashSet();
ITEM_ID与FILENAME应该实在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 images = new ArrayList();
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 images = new HashMap();
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 images = new TreeSet();
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" //SQL的keyword.
)
private Set images = new HashSet();
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 images = new HashSet();
对于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 images = new ArrayList();
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)
name="Bid"
table="BID">
...
many-to-one //多个bid对应一个item.
name="item"
column="ITEM_ID"
class="Item"
not-null="true"/>
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:
name="Item"
table="ITEM">
...
set name="bids">
The inverse attribute tells Hibernate that the collection
is a mirror image of the 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 bids = new HashSet();
...
}
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 (立即持久化)
name="Item"
table="ITEM">
...
inverse="true"
cascade="save-update"> //(单边的,此处对于bid来说,不保证另外一边,需要时两边都加)
添加一个item时,同样会更新bid端.
public class Item {
...
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, //对于bid来说
mappedBy = "item")
private Set bids = new HashSet();
...
}
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
下面是关于cascade与inverse的区别
What is the effect of cascade on inverse? Many 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 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:
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 bids = new HashSet();
...
}
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,User与Bid也有关系,上面就不能这样删除了,会有异常.
先要找到那些与bid有关的User,再在user与bid的关系里一次删除bid.最后才能
正常删除这个item.
Item anItem = // Load an item
// Delete all the referenced bids
for ( Iterator 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 ). With an idbag> mapping, even the tables
look the same:(利用idbag解决)
name="Item"
table="ITEM">
...
idbag name="bids" table="BID">
...
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:
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 bids = new HashSet();
...
}
Finally, let’s look at the mapping in a JPA XML descriptor:
...
...
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/31712/showart_454100.html |
|