简体   繁体   中英

Spring Data JPA strange behavior

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM