Na wstępie uprzedzam że nie jestem dobrze obeznany z Spring i JPA/Hibernate dopiero się wdrażam, więc mój kod może być "brzydki architektonicznie" nie mam opanowanego wzorca budowy aplikacji dla Spring :) . W kontrolerze otrzymuję zmapowany z JSONa obiekt. Który chcę zapisać do bazy. Fragment który chcę zapisać wygląda w ten sposób:
REATE TABLE IF NOT EXISTS `journal_entry` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`vehicle_journal` bigint(20) NOT NULL,
`cost` int(10) unsigned DEFAULT NULL,
`type` tinyint(3) unsigned DEFAULT NULL,
`name` varchar(25) DEFAULT NULL,
`fuel_amount_added` float DEFAULT NULL,
`unit_price` int(11) DEFAULT NULL,
`fuel_type` tinyint(4) DEFAULT NULL,
`full_filled` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_journal_entry_type` (`type`),
KEY `fk_ft` (`fuel_type`),
CONSTRAINT `fk_ft` FOREIGN KEY (`fuel_type`) REFERENCES `fuel_type` (`id`),
CONSTRAINT `fk_vehicle_journal` FOREIGN KEY (`vehicle_journal_id`) REFERENCES `vehicle_journal` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `vehicle_journal` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`vehicle` bigint(20) NOT NULL,
`created` timestamp NOT NULL DEFAULT current_timestamp(),
`updated` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
`milage` int(10) unsigned DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`entry_time` timestamp NULL DEFAULT NULL,
`place` varchar(25) DEFAULT NULL,
`total_cost` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_vehicle` (`vehicle`),
CONSTRAINT `fk_vehicle` FOREIGN KEY (`vehicle`) REFERENCES `vehicle` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
A w kodzie wygląda to tak:
@Table
@Entity
public class JournalEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer cost;
@ManyToOne(fetch=FetchType.EAGER, optional=false)
@JoinColumn(name="vehicle_journal", referencedColumnName="id", nullable=false)
private VehicleJournal vehicleJournal;
@Size(max=25)
private String name;
private Float fuelAmountAdded;
private Integer unitPrice;
@ManyToOne
@JoinColumn(name="fuel_type", referencedColumnName="id")
private FuelType fuelType;
@Column(name="full_filled")
private Boolean fullfiled;
//...
@Table
@Entity
public class VehicleJournal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name="vehicle", referencedColumnName="id")
private Vehicle vehicle;
@DateTimeFormat
@CreationTimestamp
private LocalDateTime created;
@DateTimeFormat
@UpdateTimestamp
private LocalDateTime updated;
private Integer milage;
@Size(max=255)
private String description;
@DateTimeFormat
private LocalDateTime entryTime;
@Size(max=25)
private String place;
private Integer totalCost;
@OneToMany(mappedBy="vehicleJournal", cascade= { CascadeType.ALL, CascadeType.PERSIST}, fetch=FetchType.LAZY)
private Set<JournalEntry> journalEntries = new HashSet<>(0);
//Fragment kontrolera
@RequestMapping(path = "/create", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> create(Principal principal, @RequestBody VehicleJournal vehicleJournal)
throws JsonProcessingException{
logger.debug("Adding new journal entry:" + jsonCustomMapper.writeValueAsString(vehicleJournal));
//TODO:Add validation
VehicleJournal savedVehicleJournal = vehicleJournalRepo.save(vehicleJournal); //interface VehicleJournalRepo extends CrudRepository<VehicleJournal, Long>
if(savedVehicleJournal==null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}else {
return new ResponseEntity<VehicleJournal>(savedVehicleJournal, HttpStatus.ACCEPTED);
}
}
Pobieranie obiektów z bazy nie stanowi problemu, problem występuje tylko podczas zapisu. JPA/Hibernate wyrzuca błąd podczas zapisu obiektu dziecka journalEntry
ponieważ pole rodzica vehicleJournal
jest wymagane a JPA/Hibernate ma tam wartość null i baza odrzuca zapis. JPA/Hibernate powinien otworzyć transakcję zapisać rodzica następnie pobrać jego id i umieścić u dzieci. Pytanie czy mam sknocone adnotacje i powiązania czy nie mam wyjścia i muszę ręcznie utworzyć transakcję i zapisywać w odpowiedniej kolejności?