如何解决更换所有孩子的父母
car
表:
wheel
表:
使用实体:
@Entity
public class Car {
@Id
private String id;
@OnetoMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
@Fetch(value = FetchMode.SUBSELECT)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "car_id")
private List<Wheel> wheels = new ArrayList<>();
public Car() {
}
public Car(String id) {
this.id = id;
}
public List<Wheel> getWheels() {
return wheels;
}
}
。
@Entity
public class Wheel {
@Id
private String id;
public Wheel() {
}
public Wheel(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
我想要的是将所有Honda
个滚轮移动到Nissan
。我尝试了很多事情,包括本地查询和TransactionTemplate
。但是,我无法使其成功运行。 @Service
的主要思想是这样(最简单的东西-我的第一次尝试-我想工作的东西):
@Service
public class CarService {
@Autowired
private CarRepository carRepository;
@Transactional
public void transferAllHondaWheelsToNissan() {
Car nissan = carRepository.findById("Nissan").get();
Car honda = carRepository.findById("Honda").get();
List<Wheel> wheels = new ArrayList<>(honda.getWheels());
wheels.forEach(w -> nissan.getWheels().add(w));
honda.getWheels().clear();
carRepository.save(honda);
carRepository.save(nissan);
}
}
调用carService.transferAllHondaWheelsToNissan
不会导致异常(就像我说的那样,我已经尝试了很多方法使其正常工作,其中许多都是导致异常的原因)。但是,该轮子被删除,该表为空。我的第一个想法是这是由@OnDelete(action = OnDeleteAction.CASCADE)
引起的。即使我删除了它,桌子仍然是空的,轮子也没了。
有没有办法改变方向盘的父级,使实体之间具有这种特定的关联?
是的,必须手动分配@Id
中的Wheel
。是的,我希望两者之间无方向性联系。
即使我将其设为双向,该表也将为空:
@OnetoMany(fetch = FetchType.LAZY,orphanRemoval = true,mappedBy = "car")
@Fetch(value = FetchMode.SUBSELECT)
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Wheel> wheels = new ArrayList<>();
在Wheel
@Entity
中:
@ManyToOne
private Car car;
@Service
:
@Service
public class CarService {
@Autowired
private CarRepository carRepository;
@Transactional
public void transferAllHondaWheelsToNissan() {
Car nissan = carRepository.findById("Nissan").get();
Car honda = carRepository.findById("Honda").get();
honda.getWheels().forEach(w -> {
w.setCar(nissan);
nissan.getWheels().add(w);
});
honda.getWheels().clear();
carRepository.save(honda);
carRepository.save(nissan);
}
}
我想遵循的概念是
- 将本田的车轮保持在温度变量中
- 本田的透明车轮
-
save
(更新)本田(提交事务???)以释放主键值 - 为日产添加车轮
- 日产商店
那么,我在做什么错了?
我知道我可以使用EntityManager
方法而不使用spring的@Transactional
,但是由于关系是LAZY
,因此我也必须注意它。另外,在主要应用程序中,关联更加“复杂”,并且需要更多的精力来完成。
编辑:
UPDATE wheel SET car_id = 'Nissan' WHERE car_id = 'Honda'
将不起作用,因为Nissan不存在(并且可以肯定)。日产也是在此过程中添加的。
解决方法
嗯,您可以使用JPA,但应该删除orphanRemoval = true
或设置orphanRemoval = false
顺便说一句。您的服务可以改善一点:
这是多余的
wheels.forEach(wheel -> {
nissan.getWheels().add(wheel);
});
=>
nissan.setWheels(wheels);
,
我处理了您的用例,并亲自创建了实体并进行了检查,对我来说很好。我正在直接使用休眠模式,但这并不重要。还使用龙目岛来减少样板代码。
以下是我的代码和测试用例:
汽车实体:
@Entity
@Getter
@Table(name = "car")
@NoArgsConstructor(access = PRIVATE)
@AllArgsConstructor(staticName = "of")
public class Car {
@Id
private Integer id;
private String name;
@OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
private List<Wheel> wheels = new ArrayList<Wheel>();
public void addWheels(List<Wheel> wheels) {
this.wheels = wheels;
}
}
车轮实体
@Entity
@Table(name = "wheel")
@NoArgsConstructor(access = PRIVATE)
@AllArgsConstructor(staticName = "of")
public class Wheel {
@Id
private Integer id;
@Column(name = "car_id")
private Integer carId;
}
使用休眠的测试用例
// Provided the Integer ID myself but should work for other type i.e String
@Test
void shouldTransferHondaWheelsToNissan() {
doInTransaction(em -> {
Car car = Car.of(1,"Honda",new ArrayList<Wheel>());
Wheel wheel1 = Wheel.of(1,1);
Wheel wheel2 = Wheel.of(2,1);
car.addWheels(Arrays.asList(wheel1,wheel2));
em.persist(car);
});
doInTransaction(em -> {
Car honda = em.find(Car.class,1);
List<Wheel> wheels = honda.getWheels();
Car nissan = Car.of(2,"Nissan",new ArrayList<>());
nissan.addWheels(new ArrayList<>(wheels));
wheels.clear();
em.persist(nissan);
});
doInTransaction(em -> {
Car nissan = em.find(Car.class,2);
Car honda = em.find(Car.class,1);
List<Wheel> hondaWheels = honda.getWheels();
List<Wheel> nissanWheels = nissan.getWheels();
Assertions.assertEquals(hondaWheels.size(),0);
Assertions.assertNotNull(nissanWheels);
Assertions.assertEquals(nissanWheels.size(),2);
});
}
已执行的Sql语句:
// Create Honda car instance
Hibernate: insert into car (name,id) values (?,?)
// Adding wheels to honda class
Hibernate: insert into wheel (car_id,?)
Hibernate: insert into wheel (car_id,?)
// when use unidirectional mapping,hibernate creates junction table
Hibernate: insert into car_wheel (Car_id,wheels_id) values (?,?)
Hibernate: insert into car_wheel (Car_id,?)
// Second transaction - Fetching honda car instance
Hibernate: select car0_.id as id1_0_0_,car0_.name as name2_0_0_ from car car0_ where car0_.id=?
// Fetching wheels for honda car instance
Hibernate: select wheels0_.Car_id as Car_id1_1_0_,wheels0_.wheels_id as wheels_i2_1_0_,wheel1_.id as id1_2_1_,wheel1_.car_id as car_id2_2_1_ from car_wheel wheels0_ inner join wheel wheel1_ on wheels0_.wheels_id=wheel1_.id where wheels0_.Car_id=?
// Creating nissan car instance
Hibernate: insert into car (name,?)
// Deleting wheels from honda
Hibernate: delete from car_wheel where Car_id=?
// Inserting into wheels of nissan
Hibernate: insert into car_wheel (Car_id,?)
// Selecting honda instance to verify
Hibernate: select car0_.id as id1_0_0_,car0_.name as name2_0_0_ from car car0_ where car0_.id=?
// Selecting nissan instance to verify
Hibernate: select car0_.id as id1_0_0_,car0_.name as name2_0_0_ from car car0_ where car0_.id=?
// select for wheels
Hibernate: select wheels0_.Car_id as Car_id1_1_0_,wheel1_.car_id as car_id2_2_1_ from car_wheel wheels0_ inner join wheel wheel1_ on wheels0_.wheels_id=wheel1_.id where wheels0_.Car_id=?
// same here
Hibernate: select wheels0_.Car_id as Car_id1_1_0_,wheel1_.car_id as car_id2_2_1_ from car_wheel wheels0_ inner join wheel wheel1_ on wheels0_.wheels_id=wheel1_.id where wheels0_.Car_id=?
我们可以清楚地看到orphanRemoval=true
是有效的,就像看到delete
语句,然后是insert
语句进入日产汽车一样。
测试中的数据库差异在于,我在存储器测试中使用了h2
。
我希望这会有所帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。