赞
踩
前面说了SpringBoot-SpringData-JPA集成
以这个项目为基础,继续SpringData的一些功能
下面说一下一对一关系 @oneToOne
单向关联:一个实体可以获得另一个实体对象
双向关联:两个实体可以相关或得对方对象
一对一关联:一个实体只能获得一个对方实体的引用
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public@interfaceOneToOne {
Class targetEntity() default void.class;
CascadeType[]cascade()default();
FetchType fetch() default EAGER;
boolean optional() default true;
String mappedBy() default "";
}
1,targetEntity 属性表示默认关联的实体类型,默认为当前标注的实体类。
2,cascade属性表示与此实体一对一关联的实体的级联样式类型。
3,fetch属性是该实体的加载方式,默认为即时加载EAGER
4,optional属性表示关联的该实体是否能够存在null值,默认为ture,如果设置为false,则该实体不能为null,
并且要配合使用@JoinColumn标记,将实体关系关系设置为唯一的,不为null而且不能更新
@OneToOne(optional=false)
@JoinColumn(name="address_id", unique=true, nullable=false, updatable=false)
private AddressEo address;
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public@interfaceJoinColumn {
String name() default "";
String referencedColumnName() default "";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
booleanupdatabledefaulttrue;
String columnDefinition() default "";
String table() default "";
}
1,@JoinColumn注释是保存表与表之间关系的字段
2,如果不设置name,默认name = 关联表的名称+”-“+关联表主键的字段名,在上面实例3,中,默认为“address_id”
默认情况下,关联实体的主键一般是用来做外键的,但如果此时不想用主键作为外键,则需要设置referencedColumnName属性,如:
create table address (
id int(20) not null auto_increament,
ref_id int(20) notn ull,
province varchar(50),
city varchar(50),
postcode varchar(50),
detail varchar(50),
primary key(id)
)
@OneToOne@JoinColumn(name="address_id", referencedColumnName="ref_id")
private AddressEO address;
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface PrimaryKeyJoinColumn {
String name() default "";
String referencedColumnName() default "";
String columnDefinition() default "";
}
以人和身份证一对一关系进为模型
用户和身份证为例模拟SpringData在实际开发中为我们带来的便利
项目包含用户User表,身份证Card表,及各自的数据库操作层,和一个测试类
表关联方式
a、若使用外键关联,则考虑默认关联,只需要加@OneToOne标记即可。
b、若使用主键关联,则需要配合@PrimaryKeyColumn注释
c、若使用字段关联,则需要配合@JoinColumn注释使用
@Entity
public class User {
//没有默认构造会报错
public User(){
}
public User(String name, Integer age, Card card) {
this.name = name;
this.age = age;
this.card = card;
}
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private Integer age;
/**
* @OneToOne:一对一关联
* cascade:级联配置
* CascadeType.PERSIST: 级联新建
* CascadeType.REMOVE : 级联删除
* CascadeType.REFRESH: 级联刷新
* CascadeType.MERGE : 级联更新
* CascadeType.ALL : 以上全部四项
* @JoinColumn:主表外键字段
* cid:Care所映射的表中的一个字段(会在User表创建一个cid字段,与Care外键关系)
*/
@OneToOne(cascade = CascadeType.REFRESH)//使用CascadeType.ALL无法保存成功
@JoinColumn(name = "cid", unique=true)
private Card card;
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

如果不做双向oneToOne,Card表不需要添加user参数及注解
@Entity
public class Card {
public Card() {
}
public Card(Integer cardId, String cardNumber) {
this.cardNumber = cardNumber;
this.cardId = cardId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer cardId;
@Column(nullable = false)
private String cardNumber;
/**
* @OneToOne:一对一关联
* mappedBy = "card":一对一配置参考了card
* mappedBy = "card"中的User类中的getCard()中的Care(去除get)
* 如果User类getCard()改为getIdCard(),这里就要写成:mappedBy = "idCard"
*/
@OneToOne(mappedBy = "card", fetch=FetchType.EAGER)
private User user;
public Integer getCardId() {
return cardId;
}
public void setCardId(Integer cardId) {
this.cardId = cardId;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

public interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name);
User findByNameAndAge(String name, Integer age);
@Query("from User u where u.name=:name")
User findUser(@Param("name") String name);
}
public interface CareRepository extends JpaRepository<Card, Long> {
Card findByCardNumber(String name);
}

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#开启SQL显示
spring.jpa.show-sql=true
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(DemoApplication.class)
public class oneToOneTest {
@Autowired
private UserRepository userRepository;
@Autowired
private CareRepository careRepository;
@Test
public void test() throws Exception {
// 创建测试数据
careRepository.save(new Card(1, "aaabbbccc"));
//保存
Card care1 = new Card();
care1.setCardId(1);
userRepository.save(new User("Test1", 20, care1));
//正向取数
User user = userRepository.findByName("Test1");
Card card = user.getCard();
Assert.assertEquals("aaabbbccc", card.getCardNumber());
//反向取数
Card care = careRepository.findByCardNumber("aaabbbccc");
User user_Temp = care.getUser();
Assert.assertEquals("Test1", user_Temp.getName());
}
}

Hibernate:
insert into card (card_number) values (?)
Hibernate:
insert into user (age, cid, name) values (?, ?, ?)
Hibernate:
select user0_.id as id1_1_, user0_.age as age2_1_, user0_.cid as cid4_1_, user0_.name as name3_1_
from user user0_
where user0_.name=?
Hibernate:
select card0_.card_id as card_id1_0_0_, card0_.card_number as card_num2_0_0_, user1_.id as id1_1_1_, user1_.age as age2_1_1_, user1_.cid as cid4_1_1_, user1_.name as name3_1_1_
from card card0_ left outer join user user1_
on card0_.card_id=user1_.cid
where card0_.card_id=?
Hibernate:
select user0_.id as id1_1_1_, user0_.age as age2_1_1_, user0_.cid as cid4_1_1_, user0_.name as name3_1_1_, card1_.card_id as card_id1_0_0_, card1_.card_number as card_num2_0_0_
from user user0_ left outer join card card1_
on user0_.cid=card1_.card_id
where user0_.cid=?
Hibernate:
select card0_.card_id as card_id1_0_, card0_.card_number as card_num2_0_
from card card0_
where card0_.card_number=?
Hibernate:
select user0_.id as id1_1_1_, user0_.age as age2_1_1_, user0_.cid as cid4_1_1_, user0_.name as name3_1_1_, card1_.card_id as card_id1_0_0_, card1_.card_number as card_num2_0_0_
from user user0_ left outer join card card1_
on user0_.cid=card1_.card_id
where user0_.cid=?

-- ----------------------------
-- Table structure for `card`
-- ----------------------------
DROP TABLE IF EXISTS `card`;
CREATE TABLE `card` (
`card_id` int(11) NOT NULL AUTO_INCREMENT,
`card_number` varchar(255) NOT NULL,
PRIMARY KEY (`card_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `card`
-- ----------------------------
BEGIN;
INSERT INTO `card` VALUES ('1', 'aaabbbccc');
COMMIT;
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`cid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UK_luurgctv320vav1gdny78j1a5` (`cid`),
CONSTRAINT `FK_luurgctv320vav1gdny78j1a5` FOREIGN KEY (`cid`) REFERENCES `card` (`card_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `user`
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES ('1', '20', 'Test1', '1');
COMMIT;

可以看到user表中有一个cid字段与Card中的card_id形成了外键关系
从Test测试结果看出,双向映射成功,即取User可以拿到Card实例,反之亦然
代码下载:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。