0

Say we have 2 classes Driver and Car with the Driver having a many-to-one relationship with the Car as follows.

@Entity
@Table(name = "driver")
public class Driver {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    private Car car;

    ...

    // getter setter ignored for brevity
}

Is there a way to set the value of car via post request for example by referencing car by its id by just JPA/Hibernate annotations? I'm still sort of new to Spring boot, so I was actually thinking of creating a new attribute Long carId and then apply @JsonIgnore to car, according to https://stackoverflow.com/a/42633336/9324939. Or is there any other suggestion or approach to get what I'm trying to achieve?

PS: In the database, they are already connected by reference.

-- in postgres

...

driver_id    BIGINTEGER    REFERENCES  car (id)

...
Oluwatobiloba
  • 297
  • 3
  • 12

2 Answers2

2

please take a look here for a sample project I made to address this:

https://github.com/Fermi-4/StackOverflow---JPA-Relationships

Once started locally, use Postman to set the car to a driver:

http://localhost:9090/api/assigncar?driverId=1&carId=1

Driver Entity - using Lombok

@Entity
@Table(name = "driver")
@Data
public class Driver {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long driverId;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Car car;
}

Car Entity - using Lombok and @JsonIgnore to prevent infinite recursion

@Entity
@Table(name = "car")
@Data
public class Car {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long carId;

    @JsonIgnore
    @OneToMany
    private List<Driver> drivers = new ArrayList<Driver>();

}

Repositories

public interface CarRepository extends JpaRepository<Car, Long> {    }
public interface DriverRepository extends JpaRepository<Driver, Long> {    }

Controller Class

@RequestMapping("/api")
@RestController
public class DriverController {

    @Autowired
    CarRepository _carRepo;

    @Autowired
    DriverRepository _driverRepo;

    @PostMapping("/assigncar")
    public Driver assignCarToDriver(@RequestParam Long driverId,@RequestParam Long carId) {
         Car car = _carRepo.findById(carId).get();
         Driver driver = _driverRepo.findById(driverId).get();
         driver.setCar(car);
         return _driverRepo.save(driver);
    }

}
Fermi-4
  • 645
  • 6
  • 10
  • and what if I don't want to apply @JsonIgnore to the drivers. Do I then explicitly need to pass `LEFT JOIN FETCH` as @Query to the `find*` methods in the Repository? and also manually validate input of `car_id` in case I don't want `car` to be nullable (thereby removing the @NotNull annotation from car)? – Oluwatobiloba Apr 01 '20 at 08:04
  • @Oluwatobiloba There are many routes to take when dealing with the infinite recursion issue doing Jackson Serialization. Read here for the options: https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion. As far as the car validation goes, it depends on your use case. If you use `@NotNull` on the Car entity then you are tightly coupling the Drivers and Cars - could there be a Driver who likes none of the Cars? That's for you to decide. You can validate the car_id by using a JPA function "existsById()". More here: https://www.baeldung.com/spring-data-exists-query – Fermi-4 Apr 01 '20 at 14:47
1

When you add new driver via post request , you can assign a new car or an existing car within your json object (you can try to add cascadeType.ALL within your @ManyToOne)

Sunshine
  • 68
  • 6