Java JPA在保存到OneToMany关系时未清除集合迭代器

Java JPA在保存到OneToMany关系时未清除集合迭代器,java,spring,jpa,persistence,javax,Java,Spring,Jpa,Persistence,Javax,我有一个基本的SpringBoot应用程序。使用Spring初始值设定项、JPA、嵌入式Tomcat、Thymeleaf模板引擎,并将包作为可执行JAR文件 我有这个域类: Entity @DiscriminatorValue("sebloc") public class SeblocDevice extends Device { /** * */ private static final long

我有一个基本的SpringBoot应用程序。使用Spring初始值设定项、JPA、嵌入式Tomcat、Thymeleaf模板引擎,并将包作为可执行JAR文件

我有这个域类:

    Entity
    @DiscriminatorValue("sebloc")
    public class SeblocDevice extends Device {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;


        public SeblocDevice() {
            super();
        }

        public SeblocDevice(String deviceKey, String devicePAC) {
            super(deviceKey, devicePAC);
        }

        @OneToMany(mappedBy = "device", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
        private Set<DeviceDriver> driverDevices = new HashSet<>();

        public Set<DeviceDriver> getDriverDevices() {
            return driverDevices;
        }

        public void setDriverDevices(Set<DeviceDriver> driverDevices) {
            this.driverDevices = driverDevices;
        }

      public void clearDriverDevices()  {
    for (DeviceDriver deviceDriver : deviceDrivers) {
        deviceDriver.setDriver(null);
        driverDevices.remove(deviceDriver);
    }

public void removeDriverDevice(DeviceDriver deviceDriver)  {
    deviceDriver.setDriver(null);
    driverDevices.remove(deviceDriver);
}
}
    ...
    }
这是JUnit测试,在上一次测试中,我排除了1个驱动程序,但得到了2个(清除所有驱动程序,然后添加1个)

我还尝试在服务级别中创建一个方法

public interface DeviceDriverRepository extends CrudRepository<DeviceDriver, Long> {

}
@Transactional
     public SeblocDevice cleanDrivers (SeblocDevice seblocDevice) {
         deviceDriverRepository.delete(seblocDevice.getDeviceDrivers());
     seblocDevice.getDeviceDrivers().clear();
     seblocDevice.setDeviceDrivers(null);
     return seblocDeviceRepository.save (seblocDevice);
     }
public interface DeviceDriverRepository扩展了crudepository{
}
@交易的
公共SeblocDevice清洁驱动程序(SeblocDevice SeblocDevice){
deviceDriverRepository.delete(seblocDevice.getDeviceDrivers());
seblocDevice.getDeviceDrivers().clear();
seblocDevice.setDeviceDrivers(空);
返回SEBLOCDEVICEPOSITORY.save(seblocDevice);
}
然后
deviceService.cleanDrivers(seblocDevice)


但是驱动程序再次出现

crizzis是正确的,您必须将设备设置为null

保持双向关联一致的最佳方法是创建方便的方法,如:

public void addDriverDevice(DeviceDriver deviceDriver)  {
    deviceDriver.setDriver(deviceDriver);
    driverDevices.add(deviceDriver);
}

public void removeDriverDevice(DeviceDriver deviceDriver)  {
    deviceDriver.setDriver(null);
    driverDevices.remove(deviceDriver);
}
如果你想清除所有的

public void clearDriverDevices()  {
    for (DeviceDriver deviceDriver : deviceDrivers) {
        deviceDriver.setDriver(null);
        driverDevices.remove(deviceDriver);
    }
}

要使代码按预期工作,您需要在
SeblocDevice.driverDevices
属性的
@OneToMany
关系中添加
orphanRemoving=true
参数,如下所示:

@OneToMany(mappedBy = "device", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    private Set<DeviceDriver> driverDevices = new HashSet<>();
@OneToMany(mappedBy=“device”,cascade=CascadeType.ALL,fetch=FetchType.EAGER,orphandremovation=true)
private Set driverDevices=new HashSet();
清楚地理解JPA映射。你需要记住,在一段关系中,总是有主人的一面。 例如,在
@OneToMany
@ManyToOne
的关系中,
@ManyToOne
是所有者,因为它引用了其他实体

基本上,实体管理器只关心所有者端的更改,即如果调用
DeviceDriver.setDevice(null)
,将执行删除。但恰恰相反 (
SeblocDevice.getDriverDevices().clear()
)不正确


因此,有一个参数,它是不言自明的。分配此参数后,实体管理器现在将作为所有者控制集合的元素,
SeblocDevice.getDriverDevices().clear()
将删除数据库中不在
SeblocDevice.getDriverDevices
集合中的DeviceDrivers,即使
DeviceDriver.device
不为空。

您可以发布
driverService
字段类型的实现吗?为什么需要一个驱动程序?您创建了一个与
SeblocDevice
关联的附加驱动程序,但从未删除已存在的驱动程序。。。我猜在调用
SeblocDevice.getDriverDevices().clear()
后,您希望现有的
DeviceDriveDriver
不再与
SeblocDevice
关联,但要实现这一点,
SeblocDevice.driverDevices
必须是关联的拥有方,当您使用双向映射时,必须在两端添加或删除项。而您的
设备服务.save
方法必须用
@Transactional
进行注释。我尝试了相同的结果,肯定是我做错了我看不到的事情
public void clearDriverDevices()  {
    for (DeviceDriver deviceDriver : deviceDrivers) {
        deviceDriver.setDriver(null);
        driverDevices.remove(deviceDriver);
    }
}
@OneToMany(mappedBy = "device", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    private Set<DeviceDriver> driverDevices = new HashSet<>();