代码之家  ›  专栏  ›  技术社区  ›  Tiago Pimenta

OneToOne双向映射外键自动填充

  •  3
  • Tiago Pimenta  · 技术社区  · 9 年前

    我在两个表之间有一对一的关系,但外键在我不需要映射的表上,DBA这样做是为了支持未来的更改。

    让我们假设我们有User和Address,现在每个用户只有一个地址,它将以这种方式映射,但DBA相信未来可能是一对多映射,因此用户的外键位于地址上,但应用程序有用户实例,这对自动获取地址很重要。

    我们做得很好,如下所示:

    @Entity
    @Table(name = "user")
    class User {
        @Id
        @Column(name = "user_id")
        private Long id;
    
        //...
    
        @OneToOne(cascade = CascadeType.MERGE, mappedBy = "user")
        private Address address; // this attribute is crucial
    }
    
    @Entity
    @Table(name = "address")
    class Address {
        @Id
        @Column(name = "address_id")
        private Long id;
    
        @OneToOne
        @JoinColumn(name = "user_id")
        private User user; // this attribute is not needed for the business at all, but mappedBy requires it
    
        //...
    
    }
    

    数据库:

    -- SQL:
    CREATE TABLE user
    (
        user_id INT NOT NULL,
        -- ...
        CONSTRAINT user_pk PRIMARY KEY (user_id)
    );
    
    CREATE TABLE address
    (
        address_id INT NOT NULL,
        user_id INT NOT NULL,
        -- ...
        CONSTRAINT address_pk PRIMARY KEY (address_id),
        CONSTRAINT address_user_id_fk FOREIGN KEY (user_id) REFERENCES user (user_id),
        CONSTRAINT address_user_id_uk UNIQUE (user_id) -- it says it's a one to one relation for now, if in the future it won't be anymore, just remove this constraint
    );
    

    问题是当用新的地址实例保存用户实例时,用户的地址属性为 null ,所以我希望Hibernate足够聪明,能够从用户的实例中为其设置值。

    我已经寻找了几天的解决方案,但仍然没有找到解决方法,同时我正在手动设置值,但我希望我不需要这样做。

    3 回复  |  直到 9 年前
        1
  •  4
  •   Dragan Bozanovic    9 年前

    标准解决方案是正确更新 bidirectional association (尽管只有拥有方需要更新关联才能保存到数据库)。添加到 Address 中的setter User 类别:

    public void setAddress(Address address) {
       this.address = address;
       address.setUser(this);
    }
    

    此外,您可能希望扩展 address 要包含的属性 PERSIST 因此它总是与其用户一起保持:

     @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "user")
     private Address address;
    

    然后,您可以为用户设置地址并持久化这两个地址:

    user.setAddress(address);
    session.persist(user);
    
        2
  •  0
  •   Bilal BBB    9 年前

    如果不需要“private User User”,请删除它并同时删除“User”实体中的mappedBy。使用单向关系。

    在您的示例中,mappedBy表示关联的所有者是“Address”实体,因此保存Adress而不是User的实例。喜欢:

    adress.setUser(user);
    session.save(adress);
    
        3
  •  0
  •   Qianlong    9 年前

    您需要添加CasecadeType。PERSIST将创建地址案例与创建用户一起进行。

    在java代码中,您需要执行以下操作:

    user.setAddress(address);
    address.setUser(user);
    session.persist(user);
    

    然后,您的用户将创建一个地址。

    如果您只想读取新创建用户的地址,则需要执行以下操作:

    // your code to persist a new User and Address
    session.flush();
    session.refresh(user);
    

    如果这不是你想要的,那么你需要分享你自己的Java代码,并给出你期望的详细描述。