已传递独立实体以持久保存JPA Spring引导保存

时间:2020-06-09 14:46:50

标签: java spring spring-boot hibernate jpa

我正在尝试保存具有所选公司和地区的用户类别。用户与公司有多对多关系,而区域则有多对多关系。 这给了我错误:分离实体传递为持久化:

我不确定是什么问题

USER:

@Entity
@Table(name = "NPRO_USUARIOS")
public class User implements Serializable {

    private static final long serialVersionUID = -1330075515340995797L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="user_seq_gen")
    @SequenceGenerator(name="user_seq_gen", sequenceName="TELCO_NPRO_USER_SEQ")
    @NotNull
    private int id_usuario;

    @NotNull
    private String nombre_usuario;

    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = @JoinColumn(name = "id_usuario"), inverseJoinColumns = @JoinColumn(name = "id_sociedad"))
    private Set<Sociedad> listaSociedad;

    @Transient
    private String sociedades;

    // Si el area es nula, el usuario estara asignado a todas las areas
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = @JoinColumn(name = "id_usuario"), inverseJoinColumns = @JoinColumn(name = "id_area"))
    private Set<Area> listAreas;

    @Transient
    private String areas;

    @NotNull
    private String matricula_usuario;

    @NotNull
    private String email_usuario;

    @ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = @JoinColumn(name = "id_usuario"), inverseJoinColumns = @JoinColumn(name = "id_rol"))
    private Set<Role> listaRoles;

    @ManyToMany(cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_PERFILES_USUARIOS", joinColumns = @JoinColumn(name = "id_usuario"), inverseJoinColumns = @JoinColumn(name = "id_pantalla"))
    private Set<Pantalla> listaPantallas;

    private LocalDateTime fecha_ultimo_acceso;
    private String observaciones;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "usuario_modif")
    private User usuario_modif;
}

公司:

@Entity
@Table(name = "NPRO_MAESTRO_SOCIEDADES")
public class Sociedad implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @NotNull
    private int id_sociedad;
    @NotNull
    private String cod_sociedad;
    @NotNull
    private String cod_sociedad_gl;
    @NotNull
    private String nombre_sociedad;
    @NotNull
    private String cif_sociedad;
    private String observaciones;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "usuario_modif")
    private User usuario_modif;

    private String activo;

    @JsonIgnore
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = @JoinColumn(name = "id_sociedad"), inverseJoinColumns = @JoinColumn(name = "id_usuario"))
    private Set<User> listaUsuarios;
}

区域:

@Entity
@Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {

    private static final long serialVersionUID = -1330075515340995797L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="area_seq_gen")
    @SequenceGenerator(name="area_seq_gen", sequenceName="TELCO_NPRO_AREAS_SEQ")
    @NotNull
    private int id_area;

    @NotNull
    private String nombre_area;

    private LocalDateTime fecha_modif;
    private String observaciones;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "usuario_modif")
    private User usuario_modif;

    @NotNull
    private String activo;

    @ManyToOne
    @JoinColumn(name="id_sociedad")
    private Sociedad sociedad;

    @JsonIgnore
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
    @JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = @JoinColumn(name = "id_area"), inverseJoinColumns = @JoinColumn(name = "id_usuario"))
    private Set<User> listaUsuarios;
    }

我正在使用springboot jpa存储库保存方法

@Override
public User save(User user) {

    return userRepository.save(user);
}

这是完整的错误: 2020-06-09 15:49:02.371 [nio-8080-exec-4] .mmaExceptionHandlerExceptionResolver:由处理程序执行引起的已解决异常:org.springframework.dao.InvalidDataAccessApiUsageException:传递给持久对象的分离实体:com.telefonica.npro。模型。区域;嵌套异常是org.hibernate.PersistentObjectException:传递给持久对象的分离实体:com.telefonica.npro.model.Area

预先感谢

编辑:

我正在此页面中阅读有关错误的信息 http://knowledgespleasure.blogspot.com/2015/06/understand-detached-entity-passed-to.html

我想我的问题是最后一个问题:

另一方面,如果要求从不添加新的子对象(如果它在数据库中不是必需的),则应删除CascadeType.PERSIST并应使用cascade = {CascadeType.MERGE,CascadeType.REFRESH}

用户始终与公司和地区相关,并且它们已经存在,不会成为新用户。 但是,如果我删除了PERSIST,那么在公共表中插入一个id为null的尝试 NPRO_USUARIOS_SOCIEDADES_AREAS

有帮助吗?

1 个答案:

答案 0 :(得分:0)

我将解释您对@ManyToManyUser实体之间的Area双向关系的问题。

  1. 一个bidirectional @ManyToMany关联应该拥有一个所有权和一个mappedBy一方。 CascadeType应该仅出现在此关联的一侧。

  2. this文章中所述,否则需要使双方同步,否则将破坏域模型关系的一致性,除非双方都正确,否则不能保证实体状态转换有效已同步。 因此,User实体定义了addArearemoveArea实体状态同步方法。

因此,您应该通过以下方式更正 User-Area @ManyToMany映射:

@Entity
@Table(name = "NPRO_USUARIOS")
public class User implements Serializable {
   // ...

   @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
   @JoinTable(name = "NPRO_USUARIOS_SOCIEDADES_AREAS", joinColumns = @JoinColumn(name = "id_usuario"), inverseJoinColumns = @JoinColumn(name = "id_area"))
   private Set<Area> listAreas;

   public User()
   {
      listAreas = new HashSet<>();
   }

   public void addArea(Area area) {
      listAreas.add(area);
      area.getUsers().add(this);
   }

   public void removeArea(Area area) {
      listAreas.remove(area);
      area.getUsers().remove(this);
   }
}

@Entity
@Table(name = "NPRO_MAESTRO_AREAS")
public class Area implements Serializable {
    // ... 

    @JsonIgnore
    @ManyToMany(mappedBy = "listAreas")
    private Set<User> listaUsuarios;
}

然后您可以通过以下方式保存新用户:

   User user = new User();
   // ...
   Area area1 = new Area();
   // ...
   user.addArea(area1);

   Area area2 = new Area();
   // ...
   user.addArea(area2);

   userRepository.save(user);

应该对 User-Sociedad 关系进行类似的修正。