# hibernate mysql demo
**Repository Path**: weishengshui/hibernate-mysql-demo
## Basic Information
- **Project Name**: hibernate mysql demo
- **Description**: hibernate mysql demo。
基于xml、annotation的hibernate demo:其中包含one-to-one、one-to-many、many-to-many映射关系的配置。独立的测试用例。
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: http://www.mkyong.com/tutorials/hibernate-tutorials/
- **GVP Project**: No
## Statistics
- **Stars**: 34
- **Forks**: 14
- **Created**: 2015-01-07
- **Last Updated**: 2025-02-28
## Categories & Tags
**Categories**: sample-code
**Tags**: None
## README
# hibernate-mysql-demo
基于maven构建的hibernate mysql demo。
基于xml、annotation的hibernate demo:其中包含one-to-one、one-to-many、many-to-many映射关系的配置。
独立的测试用例。
内容如下:
* one-to-one: xml/annotation。
* one-to-many: xml/annotation。
* many-to-many: xml/annotation。
* many-to-many "join table extra column": annotation。中间实体有复合主键,还包含了额外的字段,比如:创建时间、创建人等。
----
### hibernate知识点
#### 理解inverse
inverse的意思是:相反、倒转;相反的、倒转的。
在hibernate xml映射配置文件里面表示由那一方维护表关系。inverse="true"表示由对方维护表关系,inverse="false"则反之。示例如下:
Member与MemberCard是一对多的关系
* 1. 关系由MemberCard维护。
Member配置。[Member.hbm.xml](http://git.oschina.net/weishengshui/hibernate-mysql-demo/blob/master/hibernate-example-xml/src/main/resources/com/hibernate/xml/entity/Member.hbm.xml)
```xml
```
MemberCard配置。[MemberCard.hbm.xml](http://git.oschina.net/weishengshui/hibernate-mysql-demo/blob/master/hibernate-example-xml/src/main/resources/com/hibernate/xml/entity/MemberCard.hbm.xml)
```xml
```
执行如下java代码
```java
Member member = new Member();
member.setMemberName("张三");
Set memberCards = new HashSet();
MemberCard card1 = new MemberCard();
card1.setCardNo("1234567890");
MemberCard card2 = new MemberCard();
card2.setCardNo("1234567891");
MemberCard card3 = new MemberCard();
card3.setCardNo("1234567892");
// 由MemberCard维护关系,必须设置Member,不然插入外键时找不到member_id
card1.setMember(member);
card2.setMember(member);
card3.setMember(member);
memberCards.add(card1);
memberCards.add(card2);
memberCards.add(card3);
member.setMemberCards(memberCards);
session.save(member);
```
得到的sql输出如下:MemberCard在插入时,把外键也插入了。
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
```
* 2. 关系由Member维护。
xml映射文件的配置大致相同,只是Member中的配置inverse="false", MemberCard中的\ not-null要设置成false。
先插入MemberCard,外键暂时为null,后期再由Member update设置MemberCard的外键,所以not-null要允许为null,不然执行不通过。
保存的java代码和上面稍有不同,MemberCard不需要设置Member了。
```java
Member member = new Member();
member.setMemberName("张三");
Set memberCards = new HashSet();
MemberCard card1 = new MemberCard();
card1.setCardNo("1234567890");
MemberCard card2 = new MemberCard();
card2.setCardNo("1234567891");
MemberCard card3 = new MemberCard();
card3.setCardNo("1234567892");
memberCards.add(card1);
memberCards.add(card2);
memberCards.add(card3);
member.setMemberCards(memberCards);
session.save(member);
```
得到的sql输出如下:多了几条update语句。
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: update member_card set member_id=? where id=?
Hibernate: update member_card set member_id=? where id=?
Hibernate: update member_card set member_id=? where id=?
```
从一对多的关系维护中,不难看出由“多端”维护关系,效率要高。
#### 理解mappedBy
也是定义由谁维护关系,这是annotation中用到的。
假设A/B实体是关系的双方,mappedBy定义在实体A中(关系的被拥有方),另一方B就是关系的拥有方,即维护关系的一方。
首先需要理解的是:mappedBy与注解@JoinColumn/@PrimaryKeyJoinColumn/@JoinTable是冲突的,不能同时在同一个属性上出现;因为
@JoinColumn/@PrimaryKeyJoinColumn/@JoinTable这几个注解是用于维护关系的,而mappedBy在关系维护方的对立面。
只要搞清楚了由谁维护关系,其余跟xml文件配置中的inverse差不多,可参考[理解inverse](http://git.oschina.net/weishengshui/hibernate-mysql-demo#%E7%90%86%E8%A7%A3inverse),
或者看源码[Member](http://git.oschina.net/weishengshui/hibernate-mysql-demo/blob/master/hibernate-example-annotation/src/main/java/com/hibernate/annotation/entity/Member.java)/[MemberCard](http://git.oschina.net/weishengshui/hibernate-mysql-demo/blob/master/hibernate-example-annotation/src/main/java/com/hibernate/annotation/entity/MemberCard.java)
#### 理解cascade
* 1. cascade定义级联操作,即"操作完自己"之后下一步做什么。
在[理解inverse](http://git.oschina.net/weishengshui/hibernate-mysql-demo#%E7%90%86%E8%A7%A3inverse)中,Member与MemberCard是一对多的关系,Member级联save-update MemberCard,所以只要保存member
```java
session.save(member);
```
memberCard也跟着保存了。
* 2. 有时我们会看到这样一个级联配置:cascade="delete-orphan"。
annotation中这样配置
```java
// orphanRemoval=true级联更新删除"脱离"的子节点
@OneToMany(mappedBy = "member", orphanRemoval=true)
@Cascade({ CascadeType.SAVE_UPDATE })
private Set memberCards;
```
或者
```java
// CascadeType.DELETE_ORPHAN级联更新删除"脱离"的子节点
@OneToMany(mappedBy = "member")
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN })
private Set memberCards;
```
比较新的版本,官方推荐使用orphanRemoval=true
```java
public enum CascadeType {
...
/** @deprecated use @OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true) */
@Deprecated
DELETE_ORPHAN,
...
}
```
这是用于删除“脱离”的子节点。
```java
Member member = (Member)session.get(Member.class, 1);
member.setMemberName("张三2");
Set memberCards = member.getMemberCards();
// 确认会员有3张会员卡
Assert.assertEquals(3, memberCards.size());
// 从中取出一张会员卡
MemberCard memberCard = memberCards.iterator().next();
// 把这张会员卡移除掉
member.getMemberCards().remove(memberCard);
session.update(member);
```
从上面的代码中可以看到只update一下member,在update member之后有一条delete语句,sql输出如下:
```sql
Hibernate: select member0_.id as id2_0_, member0_.member_name as member2_2_0_ from member member0_ where member0_.id=?
Hibernate: select membercard0_.member_id as member3_2_1_, membercard0_.id as id1_, membercard0_.id as id3_0_, membercard0_.card_no as card2_3_0_, membercard0_.member_id as member3_3_0_ from member_card membercard0_ where membercard0_.member_id=?
Hibernate: update member set member_name=? where id=?
Hibernate: delete from member_card where id=?
```
* 3. cascade:JPA & Hibernate annotation。
这里是很容易让人误解的地方。
JPA cascade: javax.persistence.CascadeType
```java
public enum CascadeType {
/** Cascade all operations */
ALL,
/** Cascade persist operation */
PERSIST,
/** Cascade merge operation */
MERGE,
/** Cascade remove operation */
REMOVE,
/** Cascade refresh operation */
REFRESH
}
```
Hibernate cascade:org.hibernate.annotations.CascadeType
```java
public enum CascadeType {
ALL,
PERSIST,
MERGE,
REMOVE,
REFRESH,
DELETE,
SAVE_UPDATE,
REPLICATE,
/** @deprecated use @OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true) */
@Deprecated
DELETE_ORPHAN,
LOCK,
/** @deprecated use javax.persistence.CascadeType.DETACH */
@Deprecated
EVICT,
DETACH
}
```
有时我们这样配置,这里应用的是JPA cascade
```java
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY, cascade={CascadeType.PERSIST})
private Set memberCards;
```
保存member,发现memberCard没有跟着保存,除非使用CascadeType.ALL,否则其他的都没有用。
```java
session.save(member);
```
sql输出
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
```
但是session.persist()却可以级联保存
```java
session.persist(member);
```
sql输出
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
```
如果我们想session.save()方法有效果,可以使用hibernate cascade:
```java
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
@Cascade({ CascadeType.SAVE_UPDATE })
private Set memberCards;
```
再试一下
```java
session.save(member);
```
sql输出
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
Hibernate: insert into member_card (id, card_no, member_id) values (null, ?, ?)
```
从上面的实践中,大概可以知道cascade的类型粗略的对应着session的一个方法。更详细的内容可以查看hibernate源码
org.hibernate.engine.Cascade/org.hibernate.engine.CascadeStyle/org.hibernate.engine.CascadingActiona
#### cascade vs inverse(mappedBy)
cascade说明级联操作,操作完自己之后下一步做什么;inverse说明由谁来维护外键的值。
#### 参数设定的几种方式
* 1. 命名参数:冒号后面跟参数名称。
setString
```java
List members = session
.createQuery("from Member where memberName=:memName")
.setString("memName", "张三").list();
```
setParameter
```java
// 自动判断参数的类型。
List members = session
.createQuery("from Member where memberName=:memName")
.setParameter("memName", "张三").list();
```
setProperties
```java
// pojo bean
Member member = new Member();
member.setMemberName("张三");
List members = session
.createQuery("from Member where memberName=:memberName")
.setProperties(member).list();
// 还有一种方式Map。
// Map params = new HashMap();
// params.put("memName", "张三");
// List members = session
// .createQuery("from Member where memberName=:memName")
// .setProperties(params).list();
```
* 2. 位置参数:基数位置从0开始。
原始JDBC中的java.sql.PreparedStatement 中的参数位置从1开始。和命名参数不同的是:命名参数可以出现多次(一个参数值可以复用),比如
memberName1=:memName and memberName2=:memName。
```java
List members = session
.createQuery("from Member where memberName=?")
.setString(0, "张三").list();
```
#### session.clear()
session维护着自己的一个局部缓存,我们一般称之为一级缓存。hibernate二级缓存是面向整个应用的全局缓存,整个系统共用一个缓存。
clear()方法就是清空session的缓存。
```java
tx = session.beginTransaction();
Member member = new Member();
member.setMemberName("张三");
session.save(member);
tx.commit();
tx = session.beginTransaction();
session.clear();
Member member2 = (Member)session.get(Member.class, 1);
// member2是因为查询重新创建的对象。
Assert.assertFalse(member2 == member);
tx.commit();
```
sql输出如下
```sql
Hibernate: insert into member (id, member_name) values (null, ?)
Hibernate: select member0_.id as id2_0_, member0_.member_name as member2_2_0_ from member member0_ where member0_.id=?
```
如果我们把session.clear();注视掉,将会只看到一条insert语句。
```java
tx = session.beginTransaction();
Member member = new Member();
member.setMemberName("张三");
session.save(member);
tx.commit();
tx = session.beginTransaction();
// session.clear();
Member member2 = (Member)session.get(Member.class, 1);
// member2是从缓存中取出的同一个member对象。
Assert.assertTrue(member2 == member);
tx.commit();
```
缓存只针对id的查询有效(不产生select),下面的java代码将只输出一条insert语句。
```java
tx = session.beginTransaction();
Member member = new Member();
member.setMemberName("张三");
session.save(member);
tx.commit();
tx = session.beginTransaction();
// session.clear();
List members = session.createQuery("from Member where id=1").list();
Member member2 = members.get(0);
// 确定两个引用指向的是同一个对象
Assert.assertTrue(member2 == member);
tx.commit();
```
而如果根据其它属性查询,还是会产生一条select sql语句;但是取出的对象和之前的对象还是同一个对象,说明还是会根据查询得到的对象的
id从缓存中取,而不是重新创建对象。
```java
tx = session.beginTransaction();
Member member = new Member();
member.setMemberName("张三");
session.save(member);
tx.commit();
tx = session.beginTransaction();
// session.clear();
List members = session.createQuery("from Member where memberName='张三'").list();
Member member2 = members.get(0);
// 确定两个引用指向的是同一个对象
Assert.assertTrue(member2 == member);
tx.commit();
```
#### session.flush()
flush()方法强制数据库和缓存同步。
如果没有手工flush(),hibernate会根据session.getFlushMode()决定何时同步,默认是FlushMode.AUTO,更多内容参考
[FlushMode API](http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/FlushMode.html)。
如果调用了session.flush(),将产生两条update语句;而如果注释掉session.flush(),就只有一条update语句。
```java
tx = session.beginTransaction();
// 原来的memberName是“张三”
member = (Member)session.get(Member.class, 1);
member.setMemberName("张三2");
session.flush();
member.setMemberName("张三3");
session.update(member);
tx.commit();
```
sql输出
```sql
Hibernate: select member0_.id as id2_0_, member0_.member_name as member2_2_0_ from member member0_ where member0_.id=?
Hibernate: update member set member_name=? where id=?
Hibernate: update member set member_name=? where id=?
```
更多内容可参考[hibernate 教程](http://www.mkyong.com/tutorials/hibernate-tutorials/)
----
### 共用的依赖配置在parent pom.xml文件里面,所有子模块都可以“继承”到,不需要重复配置。
```xml
4.0.0
com.wss.lsl.hibernate.mysql.demo
hibernate-mysql-demo
0.0.1-SNAPSHOT
pom
hibernate-mysql-demo
http://maven.apache.org
hibernate-example-xml
hibernate-example-annotation
JBoss repository
http://repository.jboss.com/maven2/
UTF-8
3.6.3.Final
3.6.3.Final
junit
junit
3.8.1
test
com.h2database
h2
1.4.184
test
mysql
mysql-connector-java
5.1.9
runtime
org.hibernate
hibernate-core
${hibernate-version}
javassist
javassist
3.12.0.GA
org.hibernate
hibernate-c3p0
${hibernate-c3p0-version}
org.slf4j
slf4j-log4j12
1.6.1
maven-compiler-plugin
2.3.2
1.6
1.6
UTF-8
```
----
## 基于xml的hibernate mysql demo
### 配置文件如下
```xml
org.hibernate.dialect.MySQLDialect
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&useUnicode=true
root
167118
false
true
4
100
100
600
600
```
### 测试采用h2内存库模式:便于测试的执行。
```xml
org.hibernate.dialect.H2Dialect
org.h2.Driver
jdbc:h2:mem:test
su
false
create-drop
true
4
100
100
600
600
```
----
## 基于annotation的hibernate mysql demo
### xml配置文件略有不同:映射方式不一样。
注意:hibernate从3.6开始xml和annotation配置的类都可以通过"org.hibernate.cfg.Configuration"读取。之前的版本annotation配置需要通过"org.hibernate.cfg.AnnotationConfiguration"读取。
```xml
```
### 实体类
* one-to-one
```java
/**
* stock: 与stockDetail是一对一的关系
*
* @author Administrator
*
*/
@Entity
@Table(name = "stock", uniqueConstraints = {
@UniqueConstraint(columnNames = "stock_code"),
@UniqueConstraint(columnNames = "stock_name") })
public class Stock implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "stock_id", unique = true, nullable = false)
private Integer stockId;
@OneToOne(mappedBy = "stock")
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE })
private StockDetail stockDetail;
@Column(name = "stock_code", length = 10, nullable = false)
private String stockCode;
@Column(name = "stock_name", length = 20, nullable = false)
private String stockName;
public Stock() {
}
public Stock(Integer stockId, StockDetail stockDetail, String stockCode,
String stockName) {
super();
this.stockId = stockId;
this.stockDetail = stockDetail;
this.stockCode = stockCode;
this.stockName = stockName;
}
// getter/setter
}
```
```java
/**
* stockDetail: 与stock是一对一的关系
*
* @author Administrator
*
*/
@Entity
@Table(name = "stock_detail", uniqueConstraints = { @UniqueConstraint(columnNames = "comp_name") })
public class StockDetail implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@Column(name = "stock_id")
@GenericGenerator(name = "generator", strategy = "foreign", parameters = @Parameter(name = "property", value = "stock"))
@GeneratedValue(generator = "generator")
private Integer stockId;
@OneToOne
@PrimaryKeyJoinColumn
private Stock stock;
@Column(name = "comp_name", length = 20, nullable = false)
private String compName;
@Column(name = "comp_desc", length = 200)
private String compDesc;
@Column(name = "remark", length = 255)
private String remark;
@Temporal(TemporalType.DATE)
@Column(name = "listed_date", length = 10)
private Date listedDate;
public StockDetail() {
}
public StockDetail(Integer stockId, Stock stock, String compName,
String compDesc, String remark, Date listedDate) {
super();
this.stockId = stockId;
this.stock = stock;
this.compName = compName;
this.compDesc = compDesc;
this.remark = remark;
this.listedDate = listedDate;
}
// getter/setter
}
```
* one-to-many
```java
/**
* 会员:与会员卡是一对多的关系
*
* @author sean
*
*/
@Entity
@Table(name = "member", uniqueConstraints = { @UniqueConstraint(columnNames = "member_name") })
public class Member implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "member_name", length = 20, nullable = false)
private String memberName;
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE })
private Set memberCards;
public Member() {
}
public Member(Integer id, String memberName, Set memberCards) {
super();
this.id = id;
this.memberName = memberName;
this.memberCards = memberCards;
}
// getter/setter
}
```
```java
/**
* 会员卡:与会员是多对一的关系
*
* @author sean
*
*/
@Entity
@Table(name = "member_card", uniqueConstraints = { @UniqueConstraint(columnNames = "card_no") })
public class MemberCard implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "card_no", length = 20, nullable = false)
private String cardNo;
@ManyToOne
@JoinColumn(name = "member_id", referencedColumnName="id")
private Member member;
public MemberCard() {
}
public MemberCard(Integer id, String cardNo, Member member) {
super();
this.id = id;
this.cardNo = cardNo;
this.member = member;
}
// getter/setter
}
```
* many-to-many
```java
/**
* 老师:与学生是多对多的关系。
*
* @author sean
*
*/
@Entity
@Table(name = "teacher", uniqueConstraints = { @UniqueConstraint(columnNames = "teacher_name") })
public class Teacher implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "teacher_name", nullable = false, length = 20)
private String teacherName;
/**
* 定义mappedBy的对方是关系的拥有方,维护关系。
*/
@ManyToMany(mappedBy = "teachers")
@OrderBy("studentName asc")
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE })
private Set students;
public Teacher() {
}
public Teacher(Integer id, String teacherName, Set students) {
super();
this.id = id;
this.teacherName = teacherName;
this.students = students;
}
// getter/setter
}
```
```java
/**
* 学生:和老师是多对多的关系
*
* @author sean
*
*/
@Entity
@Table(name = "student", uniqueConstraints = { @UniqueConstraint(columnNames = { "student_name" }) })
public class Student implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "student_name", nullable = false, length = 20)
private String studentName;
/**
* mappedBy定义在被拥有方:老师拥有学生。
*/
@ManyToMany(fetch = FetchType.LAZY)
@OrderBy("teacherName asc")
@JoinTable(name = "teacher_student", joinColumns = @JoinColumn(name = "student_id", nullable = false, updatable = false), inverseJoinColumns = @JoinColumn(name = "teacher_id", nullable = false, updatable = false))
private Set teachers;
public Student() {
}
public Student(Integer id, String studentName, Set teachers) {
super();
this.id = id;
this.studentName = studentName;
this.teachers = teachers;
}
// getter/setter
}
```
* many-to-many(extra column):中间表有额外的字段。
```java
/**
* 代理商:与客户是多对多的关系,中间实体AgentCustomer有除关系的额外字段
*
* @author Administrator
*
*/
@Entity
@Table(name = "agent", uniqueConstraints = { @UniqueConstraint(columnNames = "agent_name") })
public class Agent implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "agent_name", length = 20, nullable = false)
private String agentName;
// orphanRemoval:级联删除孤立节点
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.agent", orphanRemoval = true)
@OrderBy("pk.customer asc")
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE })
private Set agentCustomers;
public Agent() {
}
public Agent(Integer id, String agentName, Set agentCustomers) {
super();
this.id = id;
this.agentName = agentName;
this.agentCustomers = agentCustomers;
}
// getter/setter
}
```
```java
/**
* 客户:和代理商是多对多的关系,中间实体AgentCustomer有除关系的额外字段
*
* @author Administrator
*
*/
@Entity
@Table(name = "customer", uniqueConstraints = { @UniqueConstraint(columnNames = "customer_name") })
public class Customer implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "customer_name", nullable = false, length = 20)
private String customerName;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.customer")
@OrderBy("pk.agent asc")
private Set agentCustomers;
public Customer() {
}
public Customer(Integer id, String customerName,
Set agentCustomers) {
super();
this.id = id;
this.customerName = customerName;
this.agentCustomers = agentCustomers;
}
// getter/setter
}
```
```java
/**
* 复合主键
*
* @author Administrator
*
*/
@Embeddable
public class AgentCustomerId implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@ManyToOne
private Agent agent;
@ManyToOne
private Customer customer;
public AgentCustomerId() {
}
public AgentCustomerId(Agent agent, Customer customer) {
super();
this.agent = agent;
this.customer = customer;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
AgentCustomerId that = (AgentCustomerId) obj;
if (agent != null ? !agent.equals(that.agent) : that.agent != null) {
return false;
}
if (customer != null ? !customer.equals(that.customer)
: that.customer != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result;
result = agent != null ? agent.hashCode() : 0;
result = 31 * result + (customer != null ? customer.hashCode() : 0);
return result;
}
// getter/setter
}
```
```java
/**
* 代理商与客户的中间关系实体
*
* @author Administrator
*
*/
@Entity
@Table(name = "agent_customer")
@AssociationOverrides({
@AssociationOverride(name = "pk.agent", joinColumns = @JoinColumn(name = "agent_id")),
@AssociationOverride(name = "pk.customer", joinColumns = @JoinColumn(name = "customer_id")) })
public class AgentCustomer implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@EmbeddedId
private AgentCustomerId pk;
@Temporal(TemporalType.DATE)
@Column(name = "created_date", length = 10, nullable = false)
private Date createdDate;
@Column(name = "created_by", length = 20, nullable = false)
private String createdBy;
public AgentCustomer() {
}
public AgentCustomer(AgentCustomerId pk, Date createdDate, String createdBy) {
super();
this.pk = pk;
this.createdDate = createdDate;
this.createdBy = createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Agent getAgent() {
return getPk().getAgent();
}
public void setAgent(Agent agent) {
getPk().setAgent(agent);
}
public Customer getCustomer() {
return getPk().getCustomer();
}
public void setCustomer(Customer customer) {
getPk().setCustomer(customer);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
AgentCustomer that = (AgentCustomer) obj;
if (getPk() != null ? !getPk().equals(that.getPk())
: that.getPk() != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return (getPk() != null ? getPk().hashCode() : 0);
}
// getter/setter
}
```