Skip to content

possibility of data loss using CrudRepository in case of nested entities as java Record #39435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ljpeters opened this issue Feb 7, 2024 · 4 comments
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid

Comments

@ljpeters
Copy link

ljpeters commented Feb 7, 2024

Hi,

I have encountered an issue that occurs in spring-boot-starter-parent 3.2.0 - 3.2.2.
It worked fine in 3.1.8 and 2.7.18.

I have the following structure:

public record Car(@Id Long id,
                  String reference,
                  Engine engine) {
}
public record Engine(@Id Long id,
                     Set<Piston> pistons) {
}
public record Piston(@Id Long id,
                     String name) {
}
create table public.car
(
    id bigint generated by default as identity constraint pk_car primary key,
    reference varchar(36) not null constraint uk_car_reference unique,
    created_at timestamp with time zone default now()
);

create table public.engine
(
    id bigint generated by default as identity constraint pk_engine primary key,
    car bigint not null constraint fk_engine_car references public.car,
    created_at timestamp with time zone default now()
);

create table public.piston
(
    id bigint generated by default as identity constraint pk_piston primary key,
    engine bigint not null constraint fk_piston_engine references public.engine,
    name text not null,
    created_at timestamp with time zone default now()
);

Create a Car without an engine to cause the id column in the engine table to always be different from the car id.

INSERT INTO public.car (id, reference) VALUES (1, 'no engine');

This is the repository that uses CrudRepository:

@Repository
public interface EngineTroubleRepository extends CrudRepository<Car, Long> {
    Optional<Car> findByReference(String reference);
}

This code creates a new Car;

        final var car = new Car(
                null,
                carReferenceProvider.get(),
                new Engine(
                        null,
                        Set.of(
                                new Piston(
                                        null,
                                        "piston1"
                                ),
                                new Piston(
                                        null,
                                        "piston2"
                                ),
                                new Piston(
                                        null,
                                        "piston3"
                                )
                        )
                ));
        engineTroubleRepository.save(car);

Next, I use a find to lookup the same Car. The save causes the pistons to be deleted.

        final var car = engineTroubleRepository.findByReference(carReference).orElseThrow(() -> Problem.builder()
                .withStatus(NOT_FOUND.value())
                .withTitle("car not found")
                .withDetail("No car with id [%s] could be found.", carReference)
                .buildException());

        engineTroubleRepository.save(car);

I think this happens:
the findByReference does a SELECT on Car, and subsequently on Engine. When selecting pistons, it takes the Car.id, instead of the Engine.id. The resulting Engine object does not have Pistons, and when doing the save(), al the pistons in the database get deleted.

@ljpeters
Copy link
Author

ljpeters commented Feb 7, 2024

If this is not the right project, could you point to the correct repository, so I can raise an issue there?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 7, 2024
@wilkinsona
Copy link
Member

If this is a Spring problem, I think it's most likely to be a problem in Spring Data JPA. That said, Hibernate's responsible for much of the SQL generation so it could be a Hibernate problem. To narrow that down, you may want to try Spring Boot 3.1.8 but with the version of Hibernate from Spring Boot 3.2.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Feb 7, 2024
@wilkinsona wilkinsona added status: invalid An issue that we don't feel is valid for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 7, 2024
@ljpeters
Copy link
Author

ljpeters commented Feb 7, 2024

Thank you for pointing me to the spring data jpa repository.

I forgot to add that I don't have Hibernate included, I think this is JDBC (spring-boot-starter-data-jdbc).

@wilkinsona
Copy link
Member

In that case, https://github.com/spring-projects/spring-data-relational would be the place to report the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants