更新孩子时如何更新jpa中双向关系所有者的fk

Posted

技术标签:

【中文标题】更新孩子时如何更新jpa中双向关系所有者的fk【英文标题】:How to update the fk of owner of bidirectional relation in jpa when child is updated 【发布时间】:2020-01-10 10:33:06 【问题描述】:

第一个定义

简单地说,我有 2 个实体,第一个是用户,第二个是地址,每个用户可以有一个或多个地址。这意味着,我想要用户和地址之间的双向 OneToMany 关系。

问题

当我更新我的用户并删除一些地址(具有 2 个地址列表的用户)时,我有一个具有 3 个地址的用户(具有 3 个地址列表的用户),然后保存用户,地址的 fk 是没有更新。

我希望我的新用户在更新后有 2 个地址,但地址没有改变。

简而言之:当我从用户更新地址表的列表时,地址表的 fk 没有更新。

用户实体(只写地址字段)

@Entity
@Table(name = TABLE_NAME)

public class User 

public static final String TABLE_NAME = "User";

//Some Fields Like ID  , name ,...

@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
@JsonManagedReference
private List<Address> addresses;

public List<Address> getAddresses() 
    return addresses;


public void setAddresses(List<Address> addresses) 
    this.addresses = addresses;


地址实体(只写用户字段)

@Entity
@Table(name = TABLE_NAME)

public class Address 
public static final String TABLE_NAME = "ADDRESS";

//Some Fields Like ID  , name ,...

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
@JsonBackReference
private User user;

public User getUser() 
    return user;


public void setUser(User user) 
    this.user = user;


服务类

@Service
public class UserService

@Autowired
UserRepository repository;

public updateUserAddress() 

    //Get User With Id of 1
    User user = repository.findById(1L);

    //Get Addresses
    List<Address> addresses = user.getAddresses();

    //Delete One Address From List
    addresses.remove(0);

    //Set New Address to User Entity
    user.setAddresses(addresses);

    //Save User 
    repository.save(user)

    //It doesn't work (List of Address of user is the same and not changed)


顺便说一句,我使用 Spring-data-jpa 和 Hibernate 作为 DAO 层。

【问题讨论】:

更改用户中地址的cascadeType或通过地址列表删除地址。 你试过orphanRemoval = true吗? 孤儿删除删除子,我不想删除行,我要更新地址表的fk。 您的默认FlushModeType 是什么?您是否尝试过明确EntityManager.flush() 我使用的是 spring 数据而不是实体管理器! 【参考方案1】:

通过在User实体中添加removeAddress方法,可以更新address表的fk,也可以保留行:

public void removeAddress(Address address) 
    address.setUser(null); // or the value you want

updateUserAddress 方法应该是这样的:

public void updateUserAddress() 

    User user = repository.findById(1L);
    List<Address> addresses = user.getAddresses();

    Address address = addresses.get(0); //the address to be removed
    user.removeAddress(address); 

    user.setAddresses(addresses);

    repository.save(user);


用户实体:

@Entity
@Table(name = "users")
public class User 
    // other fields

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch=FetchType.EAGER)
    @JsonManagedReference
    private List<Address> addresses;

    // getters, setters, constructors etc.

    // the remove method
    public void removeAddress(Address address) 
        address.setUser(null);
    

地址实体:

@Entity
@Table(name = "address")
public class Address 
    // other fields

    @ManyToOne
    @JoinColumn(name = "user_id")
    @JsonBackReference
    private User user;

    // getters, setters, constructors etc.

【讨论】:

以上是关于更新孩子时如何更新jpa中双向关系所有者的fk的主要内容,如果未能解决你的问题,请参考以下文章

JPA:持久化/更新孩子期间的事件通知?

如何更新链接到多个表的 FK - 更新时的级联

JPA - 更新孩子对父母的引用

JPA:在父子关系中->父未更新

spring boot jpa中的多对一映射中的外键未在子表中更新

Doctrine ManyToMany 自引用双向 - 父级未更新