10.2.2 实现Domain Object

10.2.2 实现Domain Object

Domain Object之间存在的关联关系,由图10.8可以清楚地看到,其中AuctionUserItem两个持久化类之间的关系尤为复杂,它们之间存在两种1对N的关系,分别是所属赢取两种关系。
下面是AuctionUser类的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package org.crazyit.auction.domain;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="auction_user")
public class AuctionUser
{
// 标识属性
@Id
@Column(name="user_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
// 用户名成员变量
private String username;
// 密码成员变量
private String userpass;
// 电子邮件成员变量
private String email;

// 根据属主关联的物品实体
@OneToMany(targetEntity=Item.class ,
mappedBy="owner")
private Set<Item> itemsByOwner = new HashSet<>();
// 根据赢取者关联的物品实体
@OneToMany(targetEntity=Item.class ,
mappedBy="winer")
private Set<Item> itemsByWiner = new HashSet<>();

// 该用户所参与的全部竞价
@OneToMany(targetEntity=Bid.class ,
mappedBy="bidUser")
private Set<Bid> bids = new HashSet<>();

// 无参数的构造器
public AuctionUser()
{
}
// 初始化全部成员变量的构造器
public AuctionUser(Integer id , String username
, String userpass , String email)
{
this.id = id;
this.username = username;
this.userpass = userpass;
this.email = email;
}

// id的setter和getter方法
public void setId(Integer id)
{
this.id = id;
}
public Integer getId()
{
return this.id;
}

// username的setter和getter方法
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return this.username;
}

// userpass的setter和getter方法
public void setUserpass(String userpass)
{
this.userpass = userpass;
}
public String getUserpass()
{
return this.userpass;
}

// email的setter和getter方法
public void setEmail(String email)
{
this.email = email;
}
public String getEmail()
{
return this.email;
}

// itemsByOwner的setter和getter方法
public void setItemsByOwner(Set<Item> itemsByOwner)
{
this.itemsByOwner = itemsByOwner;
}
public Set<Item> getItemsByOwner()
{
return this.itemsByOwner;
}

// itemsByWiner的setter和getter方法
public void setItemsByWiner(Set<Item> itemsByWiner)
{
this.itemsByWiner = itemsByWiner;
}
public Set<Item> getItemsByWiner()
{
return this.itemsByWiner;
}

// bids的setter和getter方法
public void setBids(Set<Bid> bids)
{
this.bids = bids;
}
public Set<Bid> getBids()
{
return this.bids;
}
}

AuctionUser 类里保留了两个Set<Item>属性:itemsByOwneritemsByWiner,其中itemsByOwner用于访问属于该用户的全部拍卖物品,而itemsByWiner用于访问该用户赢取的全部拍卖物品,这两个属性的关联实体都是Item。此外,AuctionUser类里还有一个bids属性,该属性用于访问该用户参与的全部竞价记录。
本示例没有使用映射文件来管理Hibernate实体,而是采用Annotation来管理持久化实体。在该程序中,在定义AuctionUser类时使用了@Entity修饰,该Annotation可将该类映射成持久化实体。除此之外,AuctionUser实体和3个关联实体存在1对N的关系,因此需要在AuctionUser类的itemsByOwneritemsByWinerbids属性上使用@OneToMany修饰。
本系统将把所有1对N关联都映射成双向关联,因此我们为3个@OneToMany元素都指定了mappedBy属性,这表明AuctionUser实体(1的一端)不控制关联关系。根据Hibernate的建议:对于双向1对N关联,不要让1的一端控制关系,而应该让N的一端控制关联关系,这样可以保证更好的性能。
Item类除了和AuctionUser之间存在两种N对1的关联关系外,还和Bid之间存在1对N的关联关系,和Kind之间存在N对1的关联关系,和State之间存在N对1的关联关系。下面是Item类的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package org.crazyit.auction.domain;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="item")
public class Item
{
// 标识属性
@Id
@Column(name="item_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
// 物品Remark
@Column(name="item_remark")
private String itemRemark;
// 物品名称
@Column(name="item_name")
private String itemName;
// 物品描述
@Column(name="item_desc")
private String itemDesc;
// 物品添加时间
private Date addtime;
// 物品结束拍卖时间
private Date endtime;
// 物品的起拍价
@Column(name="init_price")
private double initPrice;
// 物品的最高价
@Column(name="max_price")
private double maxPrice;

// 该物品的所有者
@ManyToOne(targetEntity=AuctionUser.class)
@JoinColumn(name="owner_id", nullable=false)
private AuctionUser owner;
// 该物品的赢取者
@ManyToOne(targetEntity=AuctionUser.class)
@JoinColumn(name="winer_id", nullable=true)
private AuctionUser winer;

// 该物品所属的种类
@ManyToOne(targetEntity=Kind.class)
@JoinColumn(name="kind_id", nullable=false)
private Kind kind;
// 该物品所处的状态
@ManyToOne(targetEntity=State.class)
@JoinColumn(name="state_id", nullable=false)
private State itemState;

// 该物品对应的全部竞价记录
@OneToMany(targetEntity=Bid.class ,
mappedBy="bidItem")
private Set<Bid> bids = new HashSet<Bid>();

// 无参数的构造器
public Item()
{
}
// 初始化全部成员变量的构造器
public Item(Integer id , String itemRemark , String itemName ,
String itemDesc , Date addtime , Date endtime ,
double initPrice , double maxPrice , AuctionUser owner)
{
this.id = id;
this.itemRemark = itemRemark;
this.itemName = itemName;
this.itemDesc = itemDesc;
this.addtime = addtime;
this.endtime = endtime;
this.initPrice = initPrice;
this.maxPrice = maxPrice;
this.owner = owner;
}

// id的setter和getter方法
public void setId(Integer id)
{
this.id = id;
}
public Integer getId()
{
return this.id;
}

// itemRemark的setter和getter方法
public void setItemRemark(String itemRemark)
{
this.itemRemark = itemRemark;
}
public String getItemRemark()
{
return this.itemRemark;
}

// itemName的setter和getter方法
public void setItemName(String itemName)
{
this.itemName = itemName;
}
public String getItemName()
{
return this.itemName;
}

// itemDesc的setter和getter方法
public void setItemDesc(String itemDesc)
{
this.itemDesc = itemDesc;
}
public String getItemDesc()
{
return this.itemDesc;
}

// addtime的setter和getter方法
public void setAddtime(Date addtime)
{
this.addtime = addtime;
}
public Date getAddtime()
{
return this.addtime;
}

// endtime的setter和getter方法
public void setEndtime(Date endtime)
{
this.endtime = endtime;
}
public Date getEndtime()
{
return this.endtime;
}

// initPrice的setter和getter方法
public void setInitPrice(double initPrice)
{
this.initPrice = initPrice;
}
public double getInitPrice()
{
return this.initPrice;
}

// maxPrice的setter和getter方法
public void setMaxPrice(double maxPrice)
{
this.maxPrice = maxPrice;
}
public double getMaxPrice()
{
return this.maxPrice;
}

// owner的setter和getter方法
public void setOwner(AuctionUser owner)
{
this.owner = owner;
}
public AuctionUser getOwner()
{
return this.owner;
}

// kind的setter和getter方法
public void setKind(Kind kind)
{
this.kind = kind;
}
public Kind getKind()
{
return this.kind;
}

// winer的setter和getter方法
public void setWiner(AuctionUser winer)
{
this.winer = winer;
}
public AuctionUser getWiner()
{
return this.winer;
}

// itemState的setter和getter方法
public void setItemState(State itemState)
{
this.itemState = itemState;
}
public State getItemState()
{
return this.itemState;
}

// bids的setter和getter方法
public void setBids(Set<Bid> bids)
{
this.bids = bids;
}
public Set<Bid> getBids()
{
return this.bids;
}
}

这里的5行粗体字代码为Item类映射了它关联的4个关联实体,其中

  • owner引用该物品的所属者,
  • winer 引用该物品的赢取者,这两个属性都引用到AuctionUser 实体。

Item 类和AuctionUserKindState之间存在N对1的关联,因此需要使用@ManyToOne来修饰这些属性;
Item类和Bid之间存在1对N的关联,因此需要使用@OneToMany来修饰该属性。

@ManyToOnefetch属性默认FetchType.EAGER,该属性将会取消延迟加载。对于N对1的关联映射,N的一端的实体只有一个关联实体,如果取消了延迟加载,那么系统加载N的一端的实体时,1的一端的实体同时也会被加载—这不会有太大的问题,因为只是额外多加载了一条记录。
@ManyToOne中取消延迟加载不会有太大的性能下降。但对于@OneToMany等修饰集合的Annotation则尽量不要取消延迟加载。一旦为修饰集合属性的Annotation取消延迟加载,则意味着加载主表记录时,引用该记录的所有从表记录也会同时被加载,这会产生一个问题:我们无法预料有多少条从表记录引用该主表记录,同时加载这些从表记录可能引起巨大的性能下降。

本系统中还有BidStateKind三个实体,但这三个实体都比ItemAuctionUser实体更简单。理解了ItemAuctionUser的映射关系,自然也就掌握了BidStateKind实体的实现方法,故此处不再赘述。