Java 冬眠。多对多给予一个;org.hibernate.PersistentObjectException分离实体传递给persist";错误

Java 冬眠。多对多给予一个;org.hibernate.PersistentObjectException分离实体传递给persist";错误,java,spring,hibernate,spring-boot,spring-data-jpa,Java,Spring,Hibernate,Spring Boot,Spring Data Jpa,我是新使用SpringBoot和Hibernate的人,我正在从事一个简单的多对多关联的项目。体育中心有许多服务设施,反之亦然。当我尝试输入类似这样的json以创建新的体育中心并关联一些现有服务时: { "name" : "SC1", "address" : "Street 1111", "description" : "A Sport center", "email" : "sc@sc.com", "phones" : [{"number" : "123456"}, {"number" : "

我是新使用SpringBoot和Hibernate的人,我正在从事一个简单的多对多关联的项目。体育中心有许多服务设施,反之亦然。当我尝试输入类似这样的json以创建新的体育中心并关联一些现有服务时:

{
"name" : "SC1",
"address" : "Street 1111",
"description" : "A Sport center",
"email" : "sc@sc.com",
"phones" : [{"number" : "123456"}, {"number" : "654321"}],
"services" : [{"idService" : 1}, {"idService" : 2}],
"commune" : {"idCommune" : 1},
"users" : [{"idUser":62}]
}
我收到这个错误:

2018-06-25 03:56:32.670 DEBUG 20696 --- [nio-8080-exec-6] org.hibernate.SQL                        : insert into sport_center (address, Commune_idCommune, description, email, name) values (?, ?, ?, ?, ?)
2018-06-25 03:56:32.671 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [Street 1111]
2018-06-25 03:56:32.671 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [1]
2018-06-25 03:56:32.671 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [A Sport center]
2018-06-25 03:56:32.671 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [sc@sc.com]
2018-06-25 03:56:32.671 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [5] as [VARCHAR] - [SC1]
2018-06-25 03:56:32.800 DEBUG 20696 --- [nio-8080-exec-6] org.hibernate.SQL                        : insert into phone (number, Sport_center_idSport_Center) values (?, ?)
2018-06-25 03:56:32.800 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [123456]
2018-06-25 03:56:32.800 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [252]
2018-06-25 03:56:32.942 DEBUG 20696 --- [nio-8080-exec-6] org.hibernate.SQL                        : insert into phone (number, Sport_center_idSport_Center) values (?, ?)
2018-06-25 03:56:32.942 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [654321]
2018-06-25 03:56:32.942 TRACE 20696 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [252]
2018-06-25 03:56:33.368 ERROR 20696 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.eiffel.canchai.model.Service; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.eiffel.canchai.model.Service] with root cause

org.hibernate.PersistentObjectException: detached entity passed to persist: com.eiffel.canchai.model.Service
值得一提的是,我已经在服务表中添加了一些行。因此,我们的想法是增加一个体育中心,并将这些服务与之关联

你能帮我做这个吗

我的课程如下:

SportCenter.java

@Entity
@Table(name = "sport_center")
public class SportCenter implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)    
@Column(name = "idSport_Center")
private Integer idSportCenter;

@Column(name = "name")
private String name;

@Column(name = "address")
private String address;

@Column(name = "description")
private String description;

@Column(name = "email")
private String email;

@JoinTable(name = "sport_center_has_user", joinColumns = {
    @JoinColumn(name = "Sport_center_idSport_Center", referencedColumnName = "idSport_Center")}, inverseJoinColumns = {
    @JoinColumn(name = "User_idUser", referencedColumnName = "idUser")})
@ManyToMany(cascade = CascadeType.ALL)
private List<User> users;


@JoinTable(name = "sport_center_has_service", joinColumns = {
@JoinColumn(name = "Sport_center_idSport_Center", referencedColumnName = "idSport_Center")}, inverseJoinColumns = {    
@JoinColumn(name = "Service_idService", referencedColumnName = "idService")})
@ManyToMany(cascade = CascadeType.ALL)    
private List<Service> services;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "sportCenter")
@JsonIgnore
private List<ImageField> imageFields;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "sportCenter")
@JsonIgnore
private List<Field> fields;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "sportCenter", fetch = FetchType.LAZY)
private List<Phone> phones;

@JoinColumn(name = "Commune_idCommune", referencedColumnName = "idCommune")
@ManyToOne(optional = false)    
private Commune commune;


public SportCenter() {
}
@Entity
@Table(name = "service")
public class Service implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)    
@Column(name = "idService")
private Integer idService;

@Column(name = "name")
private String name;           

@ManyToMany(fetch = FetchType.LAZY, mappedBy = "services", cascade = CascadeType.ALL) 
@JsonIgnore
private List<SportCenter> sportCenters;

public Service() {
}
@Repository
@Transactional
public class ServiceDao implements IServiceDao {

@PersistenceContext
private EntityManager entityManager;

@Override
public void save(Service entity) {
    entityManager.persist(entity);      
}
SportCenterDao
与上面的几乎相同:)

控制器

@Controller
@RequestMapping("/sportcenter")
@CrossOrigin
public class SportCenterController {

@Autowired
private ISportCenterService  sportCenterService;

@PostMapping("/register")
public ResponseEntity<?> registerSportCenter(@RequestBody SportCenter sc){      
    if (sc.getEmail().length() == 0 || sc.getName().length() == 0 || sc.getAddress().length() == 0 || sc.getPhones().size() == 0 || sc.getServices().size() == 0) {
        return new ResponseEntity(new ErrorMsg("Check parameters. One of them is missing"),HttpStatus.NO_CONTENT);
    }

    for (Phone p : sc.getPhones()) {
        p.setSportCenter(sc);           
    }

    for (Service s : sc.getServices()) {
        s.addSportCenters(sc);              
    }

    sportCenterService.save(sc);
    return new ResponseEntity(HttpStatus.OK);
}
@控制器
@请求映射(“/sportcenter”)
@交叉起源
公共类SportCenter控制器{
@自动连线
私人iPortcenterService sportCenterService;
@后映射(“/寄存器”)
公共响应注册中心体育中心(@RequestBody SportCenter sc){
如果(sc.getEmail().length()==0 | | sc.getName().length()==0 | | sc.getAddress().length()==0 | | sc.getPhones().size()==0 | | sc.getServices().size()=0){
返回新的ResponseEntity(新的ErrorMsg(“检查参数,其中一个丢失”)、HttpStatus.NO_内容);
}
对于(电话p:sc.getPhones()){
p、 体育中心;
}
对于(服务s:sc.getServices()){
s、 体育中心(sc);
}
sportCenterService.save(sc);
返回新的响应状态(HttpStatus.OK);
}
我认为这可能是映射关联的错误,但我不确定

另外,如果您发现有改进我的代码的方法,请让我知道:)…建议总是好的

我使用的是SpringBootV2.0.3和Hibernate5.3


提前感谢!

这里的问题是您正在将persist事件从父级级联到子级

当子实体具有非零ID时,hibernate将假定它已经存在。 由于您是从rest服务获取数据,我猜子“服务”实体没有分离。因此出现了错误“分离的实体传递到持久化”


您需要首先持久化父级,通过merge调用管理子级,然后将父级链接到子实体,或者取消Cascade.All。

Id为1和2的服务是否确实存在?如果不存在,这可能就是原因。如果存在,您可能需要使用URL引用它们。因为我希望当前的API usage将它们的所有属性都设置为
null
Rest@JensSchauder是的,它们是存在的。对不起,我不明白。你用URL引用它们是什么意思?类似这样的:@Jenschauder非常感谢你的回答!我不知道我能做到:)…我没有确实如此,但这对我找出问题所在帮助很大。再次感谢!!