我在下面有三個 Hibernate @Entity,它們模仿了我的生產應用程式中的失敗:
@Entity
@Data
@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dog extends Animal {
String barkType;
}
物體對Dog此類使用 JOINED 繼承Animal:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "uuid-char")
private UUID id;
@OneToMany(cascade = CascadeType.REMOVE)
@JoinColumn(name = "animalId", referencedColumnName = "id", insertable = false, updatable = false)
@Builder.Default
private List<Toy> toys = new ArrayList<>();
}
該Toy物體與父類相關,Animal
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Toy {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "uuid-char")
private UUID id;
@Type(type = "uuid-char")
private UUID animalId;
private String shape;
}
這是我正在測驗的實作:
@Service
@AllArgsConstructor
public class DogService {
DogRepository repository;
ToyRepository toyRepository;
@Transactional
public Dog saveDogDTO(DogDTO dogDTO) {
Dog entity = Dog.builder()
.barkType(dogDTO.getBarkType())
.build();
repository.save(entity);
toyRepository.save(Toy.builder()
.shape(dogDTO.getToyShape())
.animalId(entity.getId())
.build());
return entity;
}
}
這是我失敗的測驗,在最后一行失敗:
@DataJpaTest
class DogServiceTests {
private DogService dogService;
@Autowired
private DogRepository dogRepository;
@Autowired
private ToyRepository toyRepository;
@Test
void save_not_working_example() {
dogService = new DogService(dogRepository, toyRepository);
var dogDTO = DogDTO.builder()
.barkType("big bark")
.toyShape("some shape")
.build();
var savedDog = dogService.saveDogDTO(dogDTO);
assertThat(dogRepository.count()).isEqualTo(1);
assertThat(toyRepository.count()).isEqualTo(1);
var findByIdResult = dogRepository.findById(savedDog.getId());
assertThat(findByIdResult.get().getToys()).hasSize(1);
}
}
測驗失敗訊息:
Expected size: 1 but was: 0 in:
[]
java.lang.AssertionError:
Expected size: 1 but was: 0 in:
[]
問題似乎是雙 JPA 存盤庫在 @Transaction 中保存沖突。有沒有辦法克服這個問題?我嘗試添加@Transactional(propagation = Propagation.NEVER)到測驗中,但后來我遇到了這個失敗:
failed to lazily initialize a collection of role: com.example.datajpatest.demo.models.Animal.toys, could not initialize proxy - no Session
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.datajpatest.demo.models.Animal.toys, could not initialize proxy - no Session
uj5u.com熱心網友回復:
@DataJpaTest已注釋@Transactional,因此您的測驗方法都包含在單個事務中,因此是單個EntityManager. 您可以通過EntityManager.detach()在savedDog使用查詢之前呼叫findById(). 您也可以通過手動設定狗的玩具來修復它DogService。這將是我的建議,因為否則遲早您可能會在生產代碼中發現相同的不一致錯誤 - 事務邊界只需移動一點,這將很難發現。@DataJpaTest指出問題在某種程度上幫了你一個忙,盡管有點間接。
最終,資料庫狀態與快取的狀態不匹配EntityManager,因此您必須清除快取才能獲得所需的結果。啟動新事務也會清除快取,這可能是生產中發生的事情。Hibernate 相信您在保存(或重繪 )時使物件圖與資料庫狀態匹配。如果它們不匹配,那么 Hibernate 在不查詢資料庫的情況下就無法知道,這將被認為是多余的和低效的。
uj5u.com熱心網友回復:
請在此處嘗試此映射:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "uuid-char")
private UUID id;
@OneToMany(mappedBy = "animal", cascade = CascadeType.REMOVE)
@Builder.Default
private List<Toy> toys = new ArrayList<>();
}
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Toy {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "uuid-char")
private UUID id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "animalId")
private Animal animal;
private String shape;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/513209.html
下一篇:如何在休眠中映射主細節?
