I'm new to JPA and Hibernate and came across strange behavior. Consider the code below.
License
entity:
@Entity
@Data
public class License {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Enumerated(EnumType.STRING)
private LicenseType type;
@Column(unique = true)
private String activationKey;
@OneToMany(mappedBy = "id", cascade = CascadeType.REMOVE)
private List<Payment> payments = new ArrayList<>();
private long productId;
private String productName;
private long term;
private long creationTimestamp;
private boolean active;
}
LicenceType
enum:
public enum LicenseType {
NAMED
}
Payment
entity:
@Entity
@Data
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
private License license;
private BigDecimal sum;
}
LicenceRepository
:
@Repository
public interface LicenseRepository extends CrudRepository<License, Long> {
}
PaymentRepository
:
@Repository
public interface PaymentRepository extends CrudRepository<Payment, Long> {
}
Bootstrap class:
@SpringBootApplication
public class LsPocApplication {
public static void main(String[] args) {
SpringApplication.run(LsPocApplication.class, args);
}
@Bean
public CommandLineRunner demo(LicenseRepository licenseRepository, PaymentRepository paymentRepository) {
return (args) -> {
License license = new License();
license.setActivationKey(UUID.randomUUID().toString());
Payment payment = new Payment();
payment.setSum(BigDecimal.valueOf(new Random().nextDouble()));
payment.setLicense(license);
paymentRepository.save(payment);
// licenseRepository.delete(license); // This does nothing
// licenseRepository.delete(license.getId()); // This deletes both licence and associated payment(s)
};
}
}
So the question is why the licenseRepository.delete(license.getId())
works as intended, but licenseRepository.delete(license)
does nothing? I assumed, they are logically equivalent. Or I'm wrong?
Please advise.
Thanks in advance!
Does your License implement Serializable? If so I think both calls will call the same method, the one intended for the id parameter. But since no License has another License as id nothing gets deleted.
The reason is that after type erasure all whats left of the nice generics are Serializable
for the id and Object
for the entity type. If the entity type also happens to implement Serializable
that method is used since it is more specific. (I have to admit there is some handwaving going on in my brain, but the idea should be about right).
That is the reason why from Spring Data 2.0 (aka Kay) the method names of changed, so this confusion can no longer happen.
Looks like Payment entity saved to database using merge. So License did not added to session and and therefore licenseRepository.delete(license) doesen't work.
Try to change this lines in Payment class:
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
private License license;
to
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private License license;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.