SpringBoot-SpringData-oneToOne

前面说了SpringBoot-SpringData-JPA集成
以这个项目为基础,继续SpringData的一些功能

下面说一下一对一关系 @oneToOne


一些概念:

单向关联:一个实体可以获得另一个实体对象
双向关联:两个实体可以相关或得对方对象
一对一关联:一个实体只能获得一个对方实体的引用

@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;

@JoinColumn注解

@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;

@PrimarKeyJoinColumn

@Target({TYPE, METHOD, FIELD}) 
@Retention(RUNTIME) 
public @interface PrimaryKeyJoinColumn { 
    String name() default ""; 
    String referencedColumnName() default ""; 
    String columnDefinition() default ""; 
}

模型

以人和身份证一对一关系进为模型
用户和身份证为例模拟SpringData在实际开发中为我们带来的便利


项目目录

项目目录

项目包含用户User表,身份证Card表,及各自的数据库操作层,和一个测试类


domain

表关联方式

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;
    }

}

DAO

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);

}

application.properties

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

Test

@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());

    }

}

运行结果

运行结果


SpringData输出的SQL:

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实例,反之亦然

代码下载:

  CSDN下载
  GitHub下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BraveWangDev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值