【问题标题】:One To One Mapping Spring Data JPA一对一映射 Spring Data JPA
【发布时间】:2020-11-23 20:44:17
【问题描述】:

我有一个关于 Spring Boot 中的一对一单向映射的问题。 我有一个 Customer 类,它具有到 Address 类的一对一单向映射。

但是当我尝试将新客户与现有地址关联时,数据库会更新。 因此,两个客户现在与一个地址相关联。

据我了解,只有一个客户应该与一个唯一地址相关联。我是否正确理解了这个概念,还是我在 Spring Boot/Spring Data JPA/Hibernate 中做错了什么?

客户

@Entity
public class Customer {
    @Id
    private Long cId;
    private String cName;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="aid")
    private Address cAddr;
    :
}

地址

@Entity
public class Address {
    @Id
    private Long aid;
    private String town;
    private String county;
    :
}

data.sql

insert into address values (100, "New York", "NY");
insert into customer values (1, "John Smith", 100);

Application.java

@Override
public void run(String... args) throws Exception {
    Customer c1 = new Customer((long)5, "Mr. Men");
    Optional<Address> a100 = ar.findById((long)100);
    c1.setcAddr(a100.get());
    cr.save(c1);
}

数据库

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa nhibernate-mapping


    【解决方案1】:

    关于如何建立@OneToOne 关系有两种选择:单向和双向:see hibernate doc

    当您向下滚动一点时,您会发现以下内容:

    当使用双向 @OneToOne 关联时,Hibernate 在获取子端时强制执行唯一约束。如果有多个子节点与同一个父节点关联,Hibernate 将抛出 org.hibernate.exception.ConstraintViolationException

    这意味着只有在获取和双向关联时才会出现异常。因为 Hibernate 会进行额外的查询来查找依赖实体,所以会找到其中的 2 个,它们不适合 @OneToOne 关系并且必须抛出异常。

    为您的实体“修复”唯一性的一种方法是使 cAddr 唯一:

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="aid", unique=true)
    private Address cAddr;
    

    如果您创建数据库表,setting hbm2ddl property 这将为aid 列添加唯一约束。

    我真的建议阅读以下内容:

    1. @OneToOne javadoc 本身提供了如何正确执行所有操作的示例(对您来说示例 1 和 2 是最有用的)
    2. 检查Vlad's blog about @OneToOne。它一定是你能找到的最好的。至少跳到“最高效的映射”一章,实现双向共享PK,使用@MapsId

    也许你会想出使用@ManyToOne 选项的想法(至少我可以想象客户可以有多个地址)

    【讨论】:

      【解决方案2】:

      这不是One-to-Many 关系。它是One-to-Many,因为一个 对象有多个 相关的对象。 Checkout this article.

      例子:

      Post.java

      @Getter
      @Setter
      @AllArgsConstructor
      @NoArgsConstructor
      @Entity
      @Table
      public class Post {
      
          @Id
          @GeneratedValue
          @Column(name = "post_id")
          private Long id;
      
          @Column
          private String postHeader;
      
          @OneToMany(
                  cascade = CascadeType.ALL,
                  orphanRemoval = true
          )
          private List<Comment> comments = new ArrayList<>();
      
          public void addComment(Comment comment) {
              comments.add(comment);
          }
      
          public void removeComment(Comment comment) {
              comments.remove(comment);
          }
      
          // equals() and hashCode()
      }
      

      评论:

      @Getter
      @Setter
      @AllArgsConstructor
      @NoArgsConstructor
      @Entity
      @Table
      public class Comment {
      
          @Id
          @GeneratedValue
          @Column(name = "postcom_id")
          private Long id;
      
          @Column
          private String text;
      
          // equals() and hashCode()
      }
      

      【讨论】:

        【解决方案3】:

        查看site 上的步骤“3. 单向一对一映射演示”,基本上是您尝试做的事情的抄本。

        【讨论】:

        • 感谢您的信息,但它没有回答在一对一映射中如何将一个表中的 2 行映射到另一个表的同一行的问题。除非我错误地理解了一对一映射?
        猜你喜欢
        • 2021-09-15
        • 2020-11-30
        • 2020-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-25
        • 2019-03-27
        相关资源
        最近更新 更多