【JPA】 @OneToOne 一对一单向关联注解

原文请点击此处


 @OneToOne 定义:一对一关系。

      生活中的一对一关系,举例:人(man) 和 宠物(pet)。前提(一人只养一个宠物)
      为什么这个一对一关系是单向的?如果,人养了宠物,那么我们通过“人”就能得到他所拥有的“宠物”的实体。但是,是不是通过“宠物”就能得到“人”的实体呢?!恐怕未必吧~因为在实际生活中,有很多走失的宠物,我们无法通过它们找到它们的主人。
     类似于上述这种情况,或者业务关系。实体间的关系是一对一,并且,我们只需要通过一个实体得到其对应的实体,而且并不需要反向执行这个操作的时候。我们就需要使用单向一对一关系。


例子:
@Entity
@Table(name = "people")
public class People (){
     
     @Id  //JPA注释: 主键 
     @GeneratedValue(strategy = GenerationType.AUTO)   //设置 id 为自增长
     private Long id;

     private String name;

     //由于,people 是这个一对一的关系的主控方,所以,在people表中添加了一个 pet 的外键。
     //通过这个外键来维护 people和pet的一对一关系,而不是用第三张码表。这个是通过@JoinColumn注释实现的。
     @OneToOne //JPA注释: 一对一 关系
     @JoinColumn(name="pet_fk" )// 在pepole中,添加一个外键 "pet_fk"
     private Pet pet;

     //省略 get / set  方法...
}



@Entity
@Table(name = "pet")
public class Pet (){
     
     @Id  
     @GeneratedValue(strategy = GenerationType.AUTO)  
     private Long id;

     private String name;

     //省略 get / set  方法...
     //因为这是一个单向的一对一关系,并且,是从 people 到 pet 的一对一关系。
     //所以,在 pet 中没有与 people 管理的 属性。也就是说,无法通过 pet 找到 people 
}

===========================测试====================================
 //省略包的引用...   PeopleDao , PetDao

public class TestSingleSideOneToOne (){
     

    //测试方法   创建----实体(人&宠物)
    public void testCreate(){
          //创建人
          People people = new People();
          people.setName("人");

          //创建宠物
          Pet bird = new Pet();
          bird.setName("鸟");
          petDao.save(bird);

          Pet cat = new Pet();
          cat.setName("猫");
          petDao.save(cat);

          Pet dog = new Pet();
          dog.setName("狗");
          petDao.save(dog);

          //此时,有了人,也有了宠物,我们终于可以让这个人领养他的宠物了。
          //就让他领养一只小
          people.setPet(dog);
          peopleDao.save(people);//保存people实体。

          //让我们来验证一下
          People testPeople = peopleDao.findByName("人");
          //得到这个人养的宠物,并调用宠物get方法,得到宠物的名字
          String petName = testPeople.getPet().getName();
          System.out.println(petName);//打印的结果必然是  “狗”  
    }


    //测试方法2  删除--- 实体(人)
    public void testDeletePeople(){
         //得到名字叫“人”的 人 的 实体
         People people = peopleDao.findByName("人");
         
         //删除实体(人)
         peopleDao.delete(people);
         
         //在方法执行过后,人这个实体被从数据库中删除了。但是,宠物的实体还存在,并没有受到任何的影响。因为,people 和 pet 是单向的一对一关系。删除人,当然不会对宠物实体造成任何影响。那么,如果我们想要删除宠物,结果还会是一样的么?请看下一个测试方法。
    }


    //测试方法3   删除----实体(宠物:鸟)  
    public void testDeleteBird(){
         //得到名字叫“鸟”的 宠物 的 实体
         Pet pet = petDao.findByName("鸟");
         
         //删除实体(宠物:鸟
         petDao.delete(pet);
         
         //验证方法
         List<Pet> pets = petDao.findAll();//得到全部的宠物实体集合
         if(pet != null){
              for(int i=0;i<pets.size();i++){
                   Pet pet = pets.get(i);//得到当前循环的宠物实体
                   System.out.println(pet.getName());//打印宠物的名字
              }
         }
         //当方法执行结束后,你会看到  "狗"  “猫” 被打印出来了。而,“鸟”的实体,已经从 表pet中被删除掉了。是不是删除每一只宠物都如此简单顺利呢?恐怕未必吧。还记得那句话么?  “打狗也得看主人啊~”
    }

    //测试方法4   删除----实体(宠物:狗)  
    //这个方法执行后,会产生异常
    public void testDeleteDog(){
         //得到名字叫“狗”的 宠物 的 实体
         Pet pet = petDao.findByName("狗");
         
         //删除实体(宠物:狗
         petDao.delete(pet);
    
         //为什么会产生异常呢?因为你只是删除了宠物这个实体,但是却没有解除关系(在people表中的外键pte_fk 还是 “狗”)。JPA不会自动的去解除关系。这是缺点,也是它的有点。可以在正常删除的时候,通过捕获异常,来达到一些业务操作。就像刚刚这种情况,在你想要删除 宠物的时候,发生了异常,就说明 有人正在饲养这只小狗。这不是被遗弃的宠物,你无权处理它。除非,它被抛弃了(关系维护端,人,解除了关系。人 实体中的pet 属性置空,关系解除。)
        //那么让我们继续往下看,看看如何正确的,删除掉宠物实体。
   }


    //测试方法4   删除----实体(宠物:狗)  
    //在方法开始前,我会告诉你。在一对一单向关系中,没有添加级联删除操作。并且还想删除 被维护端。这是一个多么不理智的行为啊。那么,随后,你就知道我为什么会这么说了。
    public void testDeleteDog2(){
         //得到名字叫“狗”的 宠物 的 实体
         Pet dog = petDao.findByName("狗");
         
         //首先,我们要得到全部人的集合
         List<People> peoList = peopleDao.findAll();
         //省略空值校验
         for(int i=0;i<peoList.size();i++){
              People peo = peoList.get(i);
              //看看谁养了这只小狗。我们要强迫他抛弃自己的小狗。
              if(peo.getPet() == dog){
                    //让他抛弃他的小狗。(从维护端解除关系)
                    peo.setPet(null);
                    //为什么保存“人”实体的操作会被注释掉呢?在置空操作后,不需要保存么?这就是JPA。只要你关系设置的正确,许多操作它都会替你完成。当小狗被删除后,小狗主人的对于属性已经是置空状态了。
                    //peopleDao.save(peo);
                    return null;
              }
         }

         //删除实体(宠物:狗
         petDao.delete(dog);//至此,那个可怜的主人,如果你想的话,你还可以重新领养一只“猫”。
         
         //省略验证方法
         //小狗被成功删除
    }
}

      在进行了,循环查找,解除关系的操作后,我们终于把这只小狗从 表pet 中删除了。但是,为了删除这只狗,我们都付出了什么。一个循环操作查找谁养了这只宠物的操作,浪费了多少资源和性能?
      之所以在删除这里,用了这么大的篇幅,就是想向大家强调,选择关系的重要性!!!如果,这是一个双向的一对一关系。那么,我可以直接通过这只小狗找到它的主人,然后让它的主人解除关系。随后就可以轻松的把它删除掉。他的主人随后也可以继续领养其他的宠物。不需要通过繁琐的循环了查找它的主人。
      通常情况下,采用 单向一对一关系,会在关系维护端添加上级联删除操作。删除主人的时候,自动删除主人领养的宠物实体。我们不关心宠物实体的维护。它的存在和消亡,应该依赖于自己的主人。当主人不消亡的时候,它也失去了存在的意义。
      对于级联操作和其他关系类型。我会再随后的文章里,继续想大家介绍。另外,对于这个不是特别恰当,且冷血的例子,请青少年朋友们,在成人的陪同下一起学习。我们应该热爱小动物。他们应该是双向的,相互关联的,那么,就让我们一起期待【JPA】@OneToOne 一对一双向关联注解

猜你喜欢

转载自blog.csdn.net/QQ70945934/article/details/77989378