I have a two entities conntected with relation one-to-one(Agency-Address). I am trying to save these two entities to database using one controller. I can save address but I can't save agency entity.
Here is my exception :
There was an unexpected error (type=Internal Server Error, status=500). not-null property references a null or transient value : com.example.demo.agency.Agency.address; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.example.demo.agency.Agency.address org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : com.example.demo.agency.Agency.address; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.example.demo.agency.Agency.address
Agency.java
package com.example.demo.agency;
import com.example.demo.address.Address;
import lombok.*;
import javax.persistence.*;
@Entity(name = "agency")
@Table(name = "agency")
@Data
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class Agency {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id",nullable = false)
private Long id;
@Column(name = "phoneNumber")
private String phoneNumber;
@Column(name = "openHours")
private String openHours;
@Column(name = "email")
private String email;
@OneToOne(fetch = FetchType.EAGER,optional = false)
@JoinColumn(name="addressid",referencedColumnName = "id",nullable = false)
private Address address;
public Agency(String phoneNumber,String openHours, String email) {
this.phoneNumber = phoneNumber;
this.openHours = openHours;
this.email = email;
}
}
Address.java
package com.example.demo.address;
import com.example.demo.agency.Agency;
import lombok.*;
import javax.persistence.*;
@Entity(name = "address")
@Table(name = "address")
@Data
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id",nullable = false)
private Long id;
@Column(name = "postalCode")
private String postalCode;
@Column(name = "street")
private String street;
@Column(name = "streetNumber")
private int streetNumber;
@OneToOne(mappedBy = "address",fetch = FetchType.LAZY,cascade = CascadeType.ALL)
private Agency agency;
public Address(String postalCode,String street,int streetNumber) {
this.postalCode = postalCode;
this.street = street;
this.streetNumber = streetNumber;
}
}
AgencyController.java
package com.example.demo.agency;
import com.example.demo.address.Address;
import com.example.demo.address.AddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.swing.*;
@Controller
public class AgencyController {
private AgencyService agencyService;
private AddressService addressService;
@Autowired
public AgencyController(AgencyService agencyService,AddressService addressService) {
this.agencyService = agencyService;
this.addressService = addressService;
}
@GetMapping("/agencies")
public String getAgencies(Model model) {
model.addAttribute("agencies",agencyService.getAgencies());
return "agencies";
}
/* GET HTTP Request for form to add new agency to database */
@GetMapping("/agencies/new")
public String newAgencyPage(Model model) {
Agency newAgency = new Agency();
Address newAddress = new Address();
model.addAttribute("agency",newAgency);
model.addAttribute("address",newAddress);
return "newAgency";
}
/* POST HTTP Request for put data to database*/
@PostMapping("/agencies/save")
public String saveAgency(@ModelAttribute("agency") Agency agency,@ModelAttribute("address") Address address) {
agencyService.saveAgency(agency);
addressService.saveAddress(address);
return "redirect:/agencies";
}
}
newAgency.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Agencies</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<div class="container">
<h2>Save Agency</h2>
<form action="#" th:action="@{/agencies/save}"
method="POST">
<input type="text" th:value="*{agency.phoneNumber}" name="phoneNumber"
placeholder="Agency Phone Number" class="form-control mb-4 col-4" >
<input type="text" th:value="*{agency.openHours}" name="openHours"
placeholder="Agency OpenHours" class="form-control mb-4 col-4">
<input type="text" th:value="*{agency.email}" name="email"
placeholder="Agency Email" class="form-control mb-4 col-4">
<input type="text" th:attr="data-department=${agency.address!=null}?${agency.address.street}:'not specified'" name="street"
placeholder="Street" class="form-control mb-4 col-4">
<input type="text" th:attr="data-department=${agency.address!=null}?${agency.address.streetNumber}:'not specified'" name="streetNumber"
placeholder="Street Number" class="form-control mb-4 col-4">
<input type="text" th:attr="data-department=${agency.address!=null}?${agency.address.postalCode}:'not specified'" name="postalCode"
placeholder="Postal Code" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Save Agency</button>
</form>
<hr>
<a th:href = "@{/agencies}"> Back to Agency List</a>
</div>
</body>
</html>
CodePudding user response:
As the exception message says, the Agency.address
property is null, although it's marked with nullable=false
attribute. Probably it's null because you don't set it anywhere to point to the address
instance.
Since your relation is bidirectional, you have to set it from both sides. I suppose you need to add something like this to your saveAgency
method:
agency.setAddress(address);
address.setAgency(agency);
agencyService.saveAgency(agency);
addressService.saveAddress(address);