我有一个有线问题,Hibernate在更新实体时触发了一些删除查询。
实体:
public class Item {
@Id
@GeneratedValue
private Long id;
@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "item_tags", joinColumns = @JoinColumn(name = "item_id"), inverseJoinColumns = @JoinColumn(name = "tag_id"))
private Set<Tag> tags = new HashSet<>();
// some more stuff
}更新实体的代码:
public Item updateItem(ItemUpdateRequest dto, long id) {
Item item = itemDao.findEntity(id);
item = ItemMapper.INSTANCE.mapFromUpdateRequest(item, dto, tagDao);
// save item so it can be returned
item = itemDao.saveEntity(item);
return item;
}由于请求只发送标签的ID,因此MapStruct使用自定义方法生成ItemMapper来加载标签:
@AfterMapping
default void loadTags(@MappingTarget Item item, ItemUpdateRequest dto, @Context TagDAO dao) {
Collection<Tag> tags = dao.findEntities(dto.getTags());
item.setTags(new HashSet<>(tags));
}因此,生成的MapStruct映射器如下所示:
@Override
public Item mapFromUpdateRequest(Item item, ItemUpdateRequest dto, TagDAO tagDao) {
if ( dto == null ) {
return null;
}
item.setDescription( dto.getDescription() );
item.setPrice( dto.getPrice() );
item.setTitle( dto.getTitle() );
item.setType( itemTypeMapper.map( dto.getType() ) );
loadTags( item, dto, tagDao );
return item;
} 如果ItemUpdateRequest不包含标记,Hibernate将执行以下查询:
1. Hibernate: update public.item set description=?, price=?,
restaurant_id=?, title=?, type=?, visible=? where id=?
2. Hibernate: select tags0_.item_id as item_id1_20_0_, tags0_.tag_id as
tag_id2_20_0_, tag1_.id as id1_41_1_, tag1_.abbreviation as
abbrevia2_41_1_, tag1_.text as text3_41_1_ from public.item_tags
tags0_ inner join public.tag tag1_ on tags0_.tag_id=tag1_.id where
tags0_.item_id=?
3. Hibernate: delete from public.item_tags where item_id=?我不明白为什么Hibernate会发出删除查询。DB和ItemUpdateRequest中的项目都不包含任何标记。我认为Hibernate可能会识别更改后的集合,因为它是在loadTags()方法中再次设置的。
我尝试编写单元测试,但此测试按预期工作,并且没有发出任何delete语句。
@Test
public void deleteQueryTest() {
Item item = Item.builder().title("Test").build();
item = itemDao.saveEntity(item);
Item reloadedItem = itemDao.findEntity(item.getId());
ItemUpdateRequest updateRequest = ItemUpdateRequest.builder()
.title("Test Changed")
.build();
reloadedItem = ItemMapper.INSTANCE.mapFromUpdateRequest(reloadedItem, updateRequest, tagDao);
reloadedItem = itemDao.saveEntity(reloadedItem);
}发布于 2021-09-13 14:12:27
loadTags方法始终设置新的集合实例,而不是更改支持脏跟踪的现有集合实例。请尝试使用item.getTags().clear(); item.getTags().addAll(tags);。除此之外,我建议您研究一下Blaze-Persistence Entity Views,它可以通过执行更少的查询来进一步提高事务性能。
我创建了这个库,以便在JPA模型和自定义接口或抽象类定义的模型之间轻松映射,就像Spring数据在类固醇上的投影一样。其思想是以您喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(Getter)映射到实体模型。
使用Blaze-Persistence实体视图,您的用例的DTO模型可能如下所示:
@EntityView(Item.class)
@UpdatableEntityView
public interface ItemDto {
@IdMapping
Long getId();
String getTitle();
void setTitle(String title);
String getDescription();
void setDescription(String description);
BigDecimal getPrice();
void setPrice(BigDecimal price);
ItemTypeDto getType();
void setType(ItemTypeDto type);
Set<TagDto> getTags();
@EntityView(ItemType.class)
interface ItemTypeDto {
@IdMapping
Long getId();
}
@EntityView(Tag.class)
@UpdatableEntityView
@CreatableEntityView
interface TagDto {
@IdMapping
Long getId();
String getAbbreviation();
void setAbbreviation(String abbreviation);
String getText();
void setText(String text);
}
}查询就是将实体视图应用于查询,最简单的就是通过id进行查询。
ItemDto a = entityViewManager.find(entityManager, ItemDto.class, id);
Spring数据集成允许您像使用Spring数据投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<ItemDto> findAll(Pageable pageable);最好的部分是,它将只获取实际需要的状态!
多亏了Jackson和Spring MVC的集成,你的代码看起来就像这样简单:
public interface ItemDtoRepository extends EntityViewRepository<ItemDto, Long> {
} @Autowired
private ItemDtoRepository itemRepository;
@RequestMapping(path = "/items/{id}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateItem(@EntityViewId("id") @RequestBody ItemDto itemDto) {
itemRepository.save(itemDto);
return ResponseEntity.ok(itemDto.getId().toString());
}有关更多详细信息,还可以查看文档:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#entity-view-deserialization
https://stackoverflow.com/questions/69136057
复制相似问题