user7918329
user7918329

Reputation:

custom save query for Spring Data (Hibernate JPA)

I have two entities:

WeeklyBoxOffice.java

 @Entity
    public class WeeklyBoxOffice {

    @NotNull
    private String country;

    @Id
    @NotNull
    private String name;

    @NotNull
    private long weeklyGross;

    @NotNull
    private double weeklyChange;

    @OneToOne//(fetch = FetchType.LAZY, cascade=CascadeType.ALL )
    @JoinColumn(name = "name")
    private Movie movie;
    }

Movie.java

 @Entity
    @Table(name = "movies")
    public class Movie {

    @Id
    @NotNull
    private String name;

    @NotNull
    private String imageLink;
    }

And following repository:

public interface WeeklyBoxOfficeRepository extends   
CrudRepository<WeeklyBoxOffice, String> {
    Iterable<WeeklyBoxOffice> findByCountryOrderByWeeklyGrossDesc(String country);
}

Existing find method works like left join, which is exactly what I need. But how to save WeeklyBoxOffice object without saving movie object? I don't really the idea of creating WeeklyBoxOfficeLite. Now it gives an exception

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : entity.WeeklyBoxOffice.movie -> entity.Movie; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : entity.WeeklyBoxOffice.movie -> entity.Movie ... Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : WeeklyBoxOffice.movie -> entity.Movie

Is it possible to use somehow NativeQuery for save method to ignore nested Movie object?

Upvotes: 0

Views: 7659

Answers (3)

Cepr0
Cepr0

Reputation: 30379

If you removed the cascade from the association with movie, then you should not get this error, imho...

But anyway maybe this workaround can help...

public class WeeklyBoxOfficeService {

    @Autoware
    private WeeklyBoxOfficeRepo repo;

    public WeeklyBoxOffice saveWithoutMovie(WeeklyBoxOffice weeklyBoxOffice) {

        weeklyBoxOffice.setMovie(null); // 'unlink' movie from BO
        repo.save(weeklyBoxOffice); // save BO without movie
    }  
}

@RestController
@RequestMapping("/weeklyBoxOffice")
public class WeeklyBoxOfficeController {

    @Autoware
    private WeeklyBoxOfficeService service;

    @PostMapping
    public ResponseEntity<?> saveWithoutMovie(@RequestBody WeeklyBoxOffice weeklyBoxOffice) {

        WeeklyBoxOffice result = service.saveWithoutMovie(weeklyBoxOffice);
        return ResponseEntity.ok(result);
    }
}

Upvotes: 1

CIPHER007
CIPHER007

Reputation: 376

I think you are also sending JSON of Movie with WeeklyBoxOffice JSON like

{
    "country": "xxxxxx",
    "name": "xxxxxxxx",
    "weeklyGross": "xxxxx",
    "weeklyChange": "xxxxxx",
    "movie": {
        "name": "xxxxxx",
        "imageLink": "xxxxx"
    }
}

So you have to first create a MovieRepository and save movie using this repository and then save WeeklyBoxOffice using WeeklyBoxOfficeRepository like this

    @Autowired
    WeeklyBoxOfficeRepository weeklyBoxOfficeRepository;
    @Autowired
    MovieRepository movieRepository;
    public WeeklyBoxOffice saveWeeklyBoxOffice(WeeklyBoxOffice weeklyBoxOffice) {
           movieRepository.save(weeklyBoxOffice.getMovie());
           return weeklyBoxOfficeRepository.save(weeklyBoxOffice);
    }

Other solution, you can use CascadeType.All for saving this JSON using only one line

weeklyBoxOfficeRepository.save(weeklyBoxOffice);

this line will automatically save and will also assign movie name(id) to weeklyBoxOffice.

Upvotes: 0

davidxxx
davidxxx

Reputation: 131436

Why not simply set to null the movie field before invoking the save() operation ?
In this way, Hibernate will ignore it during the flush.

Upvotes: 0

Related Questions