10.2.2 实现Domain Object
各Domain Object
之间存在的关联关系,由图10.8可以清楚地看到,其中AuctionUser
和Item
两个持久化类之间的关系尤为复杂,它们之间存在两种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; }
public void setId(Integer id) { this.id = id; } public Integer getId() { return this.id; }
public void setUsername(String username) { this.username = username; } public String getUsername() { return this.username; }
public void setUserpass(String userpass) { this.userpass = userpass; } public String getUserpass() { return this.userpass; }
public void setEmail(String email) { this.email = email; } public String getEmail() { return this.email; }
public void setItemsByOwner(Set<Item> itemsByOwner) { this.itemsByOwner = itemsByOwner; } public Set<Item> getItemsByOwner() { return this.itemsByOwner; }
public void setItemsByWiner(Set<Item> itemsByWiner) { this.itemsByWiner = itemsByWiner; } public Set<Item> getItemsByWiner() { return this.itemsByWiner; }
public void setBids(Set<Bid> bids) { this.bids = bids; } public Set<Bid> getBids() { return this.bids; } }
|
在AuctionUser
类里保留了两个Set<Item>
属性:itemsByOwner
和itemsByWiner
,其中itemsByOwner
用于访问属于该用户的全部拍卖物品,而itemsByWiner
用于访问该用户赢取的全部拍卖物品,这两个属性的关联实体都是Item
。此外,AuctionUser
类里还有一个bids
属性,该属性用于访问该用户参与的全部竞价记录。
本示例没有使用映射文件来管理Hibernate
实体,而是采用Annotation
来管理持久化实体。在该程序中,在定义AuctionUser
类时使用了@Entity
修饰,该Annotation
可将该类映射成持久化实体。除此之外,AuctionUser
实体和3个关联实体存在1对N的关系,因此需要在AuctionUser
类的itemsByOwner
、itemsByWiner
和bids
属性上使用@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; @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; }
public void setId(Integer id) { this.id = id; } public Integer getId() { return this.id; }
public void setItemRemark(String itemRemark) { this.itemRemark = itemRemark; } public String getItemRemark() { return this.itemRemark; }
public void setItemName(String itemName) { this.itemName = itemName; } public String getItemName() { return this.itemName; }
public void setItemDesc(String itemDesc) { this.itemDesc = itemDesc; } public String getItemDesc() { return this.itemDesc; }
public void setAddtime(Date addtime) { this.addtime = addtime; } public Date getAddtime() { return this.addtime; }
public void setEndtime(Date endtime) { this.endtime = endtime; } public Date getEndtime() { return this.endtime; }
public void setInitPrice(double initPrice) { this.initPrice = initPrice; } public double getInitPrice() { return this.initPrice; }
public void setMaxPrice(double maxPrice) { this.maxPrice = maxPrice; } public double getMaxPrice() { return this.maxPrice; }
public void setOwner(AuctionUser owner) { this.owner = owner; } public AuctionUser getOwner() { return this.owner; }
public void setKind(Kind kind) { this.kind = kind; } public Kind getKind() { return this.kind; }
public void setWiner(AuctionUser winer) { this.winer = winer; } public AuctionUser getWiner() { return this.winer; }
public void setItemState(State itemState) { this.itemState = itemState; } public State getItemState() { return this.itemState; }
public void setBids(Set<Bid> bids) { this.bids = bids; } public Set<Bid> getBids() { return this.bids; } }
|
这里的5行粗体字代码为Item
类映射了它关联的4个关联实体,其中
owner
引用该物品的所属者,
winer
引用该物品的赢取者,这两个属性都引用到AuctionUser
实体。
Item
类和AuctionUser
、Kind
、State
之间存在N对1
的关联,因此需要使用@ManyToOne
来修饰这些属性;
Item
类和Bid
之间存在1对N
的关联,因此需要使用@OneToMany
来修饰该属性。
@ManyToOne
的fetch
属性默认为FetchType.EAGER
,该属性将会取消延迟加载。对于N对1的关联映射,N的一端的实体只有一个关联实体,如果取消了延迟加载,那么系统加载N的一端的实体时,1的一端的实体同时也会被加载—这不会有太大的问题,因为只是额外多加载了一条记录。
在@ManyToOne
中取消延迟加载不会有太大的性能下降。但对于@OneToMany
等修饰集合的Annotation
则尽量不要取消延迟加载。一旦为修饰集合属性的Annotation
取消延迟加载,则意味着加载主表记录时,引用该记录的所有从表记录也会同时被加载,这会产生一个问题:我们无法预料有多少条从表记录引用该主表记录,同时加载这些从表记录可能引起巨大的性能下降。
本系统中还有Bid
、State
和Kind
三个实体,但这三个实体都比Item
和AuctionUser
实体更简单。理解了Item
和AuctionUser
的映射关系,自然也就掌握了Bid
、State
和Kind
实体的实现方法,故此处不再赘述。
原文链接: 10.2.2 实现Domain Object