JPA错误:InvalidDataAccessApiUsageException:分离的实体传递给持久化

时间:2019-01-28 15:43:53

标签: java spring hibernate jpa

我使用oneToMany注释将两个实体相互映射。一个实体为bookedBus,第二个实体为drivers。驱动程序实体将已经插入了一行,该行随后将成为bookedBus实体(PK)的外部引用(FK)。为简洁起见,以下是两个实体,即setter和getter。

第一个实体

@Entity
@Table(name = "bookedBuses")
public class BookedBuses implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "driver_id")
    private Drivers driver;
}

第二个实体

@Entity
public class Drivers implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "driver")
    private List<BookedBuses> bookedBus;
}

现在,当我尝试保存到已预订的巴士实体时,它将引发以下异常

  

org.springframework.dao.InvalidDataAccessApiUsageException:传递给持久对象的分离实体:com.bus.api.entity.Drivers;嵌套异常是org.hibernate.PersistentObjectException:传递给持久对象的分离实体:com.bus.api.entity.Drivers

下面是我尝试保存到bookedBus实体的方法

BookedBuses bookedRecord = new BookedBuses();
bookedRecord.setBookedSeats(1);
bookedRecord.setBookedBusState(BookedBusState.LOADING);
      bookedRecord.setBus(busService.getBusByPlateNumber(booking.getPlateNumber()));
bookedRecord.setRoute(booking.getRoute());
 infoLogger.info("GETTING DRIVER ID ======= " +    booking.getDriver().getId());
 Drivers drivers = new Drivers(booking.getDriver().getId());
 List<BookedBuses> d_bu = new ArrayList<>();
 drivers.setBooked(d_bu);
 drivers.addBooked(bookedRecord);
 bookedRecord.setDriver(drivers);
 bookedBusService.save(bookedRecord);

我的BookBusService保存方法按要求

@Autowired
private BookedBusRepository bookedBusRepo;
public boolean save(BookedBuses bookedRecord) {
    try {
        bookedBusRepo.save(bookedRecord);
        return true;
    } catch (DataIntegrityViolationException ex) {
        System.out.println(ex);
        AppConfig.LOGGER.error(ex);
        return false;
        // Log error message
    }
}

2 个答案:

答案 0 :(得分:1)

首先,您在命名上有些混淆:您有DriverDrivers。像这样:

private Drivers driver;

还要选择这样的变量名:

BookedBuses bookedRecord = new BookedBuses();

会引起很多混乱。不要在类型之间混合使用单数形式和单数形式,最好也不要引入像记录这样可能不容易关联的名称。还有这个:

private List<BookedBuses> bookedBus;

应该像这样:

private List<BookedBus> bookedBuses;

(而且我还需要更改您的班级名称BookedBuses-> BookedBus)

无论如何,实际的问题似乎在这里:

Drivers drivers = new Drivers(booking.getDriver().getId());

您需要借助存储库通过id来获取现有实体,而不是创建一个具有id的新实体。像这样:

Drivers drivers = driverRepo.findOne(booking.getDriver().getId()); // or findById(..)

似乎您有一个未显示的构造函数,可以使用id创建驱动程序。如果不进行管理,则认为已分离。 (您还有drivers.addBooked(bookedRecord);,但您没有分享,但也许微不足道)

请注意,有些帖子建议将CascadeType.ALL更改为CascadeType.MERGE是否有效取决于您的需求。 Spring数据可以基于实体ID在save(..)上进行一些合并,但在这种情况下不一定如此。

答案 1 :(得分:1)

此行

Drivers drivers = new Drivers(booking.getDriver().getId());

如果您已经有了可用的驱动程序ID,则无需再次从数据库中提取驱动程序ID。

Cascade@OneToMany删除@ManyToOne属性后,您的代码应该可以使用。

@Entity
@Table(name = "bookedBuses")
public class BookedBuses implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
`
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "driver_id")
    private Drivers driver;
}

@Entity
public class Drivers implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "driver_id")
    private List<BookedBuses> bookedBus;
}