创建父实体时@OneToMany Pesist Child

Posted

技术标签:

【中文标题】创建父实体时@OneToMany Pesist Child【英文标题】:@OneToMany Pesist Child when creating Parent Entity 【发布时间】:2019-07-27 03:29:40 【问题描述】:

我有一个 OneToMany 关系(用户到电子邮件地址)

也许我做错了,我的数据库是空的,但是如果我想发布一个用户对象并将其添加到数据库中,连同 emailAdresses 对象并保留 EmailAddress 。

我想要数据库中的 2 条记录: 1 个用户和 1 个电子邮件地址(带有一个指向用户表的 fk)

服务类

目前我为使其工作而实施的是:

@Service
public class UserService 

private UserRepository userRepository;
private ModelMapper modelMapper;

   public UserService(UserRepository userRepository, ModelMapper modelMapper) 
      this.userRepository = userRepository;
      this.modelMapper = modelMapper;

      //Used for mapping List
      modelMapper.getConfiguration()
              .setFieldMatchingEnabled(true)
              .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE)
              .setSourceNamingConvention(NamingConventions.JAVABEANS_MUTATOR);

  
  public User createUser(UserCreateDTO userCreateDTO) 

      User user = modelMapper.map(userCreateDTO, User.class);
      //persist User to EmailAddress object
      if(user.getEmailAddresses() != null)
          user.getEmailAddresses().forEach(user::persistUser);
      

      return userRepository.save(user);
  

  public UserDTO getUserById(Long id) 
      User found = userRepository.findById(id).get();
      return modelMapper.map(found, UserDTO.class);
  
  // .....

我见过在一些双向关系中使用的

用户实体

@Entity
@Table(name = "Users")
@Getter @Setter @ToString @NoArgsConstructor
public class User 

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "user_id", updatable = false, nullable = false)
   private Long id;

   private String firstName;
   private String lastName;
   private int age;

   @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
   private List<EmailAddress> emailAddresses;

电子邮件地址实体

@Entity
@Table(name = "Email")
@Getter @Setter @ToString @NoArgsConstructor
public class EmailAddress 

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name="email_id", updatable = false, nullable = false)
   private Long emailId;
   private String email;

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST )
   @JoinColumn(name = "user_id", nullable = false)
   @JsonIgnore
   private User user;

有没有更好的方法来建立 Join 关系?

POST 请求示例

"firstName":"Joe", "lastName":"Bloggs", "age": 30, "emailAddresses" : [ "joe-private@email.com" , "joe-work@email.com" ] 

【问题讨论】:

你是持久化用户还是检索用户?您可以在实际调用 entityManager 或 Spring 存储库的位置添加服务类吗? 我认为 this question 几乎可以复制到你的。 【参考方案1】:

我猜您还需要将此电子邮件与用户相关联,而不仅仅是将用户设置为电子邮件实体。

public void persistUser(EmailAddress emailAddress) 
    // set this email to the user
    // if email EmailAddresses list is null you might need to init it first
    this.getEmailAddresses().add(emailAddress);   
    emailAddress.setUser(this);

【讨论】:

我也有这个。但是当我通过 ID 获取用户时。它会返回 2 个电子邮件元素……不知道为什么会这样。另外,我只在请求中存在 emailAddresses 时才调用此方法【参考方案2】:

首先,我认为persistUser 方法不应该是服务层的一部分——由于它的实现,它主要类似于应该在User 实体类中实现的Domain 层方法。 其次,由于它是 POST 方法,您不应该关心电子邮件的存在 - 您正在添加一个新用户和一组新的电子邮件 接近一个问题,我建议你试试这个:

public class UserService 

  /************/
  @Autowired
  private UserManager userManager;

  public void addUser(UserModel model) 
    User user = new User(model);
    List<EmailAddress> emails = model.getEmailAddresses().stream().map(EmailAddress::new).collect(Collectors.toList());
    user.setEmailAddresses(emails);
    userManager.saveUser(user);
    

并在User 添加:

public void setEmailAddresses(List<EmailAddress> emails) 
  emails.forEach(item -> item.setUser(this));
  this.emailAddresses = emails;

并且不要忘记为具有模型参数的实体实现构造函数

【讨论】:

以上是关于创建父实体时@OneToMany Pesist Child的主要内容,如果未能解决你的问题,请参考以下文章

@OneToMany 和 @ElementCollection 之间的区别?

Hibernate - 是不是需要在父实体中包含 Set 和 OneToMany 注释?

具有父复合 pk 的 JPA OneToMany 是子主键派生实体问题的一部分

OneToMany 关系中的休眠标准

@OneToMany 映射休眠中的集合

JPA OneToMany 不删除孩子