I have 2 entity classes like below. After the parent object is persisted,
accessing the foreign key referenced object returns null.The entity classes are as below.
I have an Employee entity class like below
#Entity
#Table(name = "employees")
public class Employee {
private long employeeId;
private String name;
private long companyId;
private Company companyByCompanyId;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
public long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(long employeeId) {
this.employeeId = employeeId;
}
#Basic
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "company_id")
public long getCompanyId() {
return companyId;
}
public void setCompanyId(long companyId) {
this.companyId = companyId;
}
#ManyToOne
#JoinColumn(name = "company_id", referencedColumnName = "company_id", nullable = false, insertable = false, updatable = false)
public Company getCompanyByCompanyId() {
return companyByCompanyId;
}
public void setCompanyByCompanyId(Company companyByCompanyId) {
this.companyByCompanyId = companyByCompanyId;
}
}
and a Company entity class like below
#Entity
#Table(name = "companies")
public class Company {
private long companyId;
private String companyName;
private Collection<Employee> employeesByCompanyId;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "company_id")
public long getCompanyId() {
return companyId;
}
public void setCompanyId(long companyId) {
this.companyId;
}
#Basic
#Column(name = "company_name")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
#OneToMany(mappedBy = "companyByCompanyId")
public Collection<Employee> getEmployeesByCompanyId() {
return employeesByCompanyId;
}
public void setEmployeesByCompanyId(Collection<Employee> employeesByCompanyId) {
this.employeesByCompanyId = employeesByCompanyId;
}
}
This is the controller method in a controller class
#ApiOperation(value="Create a new employee")
#ApiResponses({})
#RequestMapping(value= "/createEmployee",method= RequestMethod.POST)
public Callable<EmployeeDTO> createEmployee(
HttpServletRequest request,
#RequestBody #Valid final List<EmployeeDTO> employeeDto) {
long employeeId = employeeService.createEmployee(employeeDto);
EmployeeDTO createdEmployee = employeeService.getEmployee(employeeId);
return () -> createdEmployee;
}
This is the method for createEmployee(employeeDto) in the service class
#Transactional
public long createEmployee(employeeDto){
Employee employee = new Employee();
employee.setName(employeeDto.getName());
employee.setCompanyId(employeeDto.getCompanyId());
Employee savedEmployee = employeeRepository.save(employee);
return savedEmployee.getEmployeeId();
}
This is the getEmployee method in the same service class as above.
public EmployeeDTO getEmployee(long employeeId) {
Employee employee = employeeRepository.findByEmployeeId(employeeId);
EmployeeDTO employeeDTO = new EmployeeDTO();
employeeDTO.setEmployeeId(employee.getEmployeeId());
employeeDTO.setName(employee.getName());
employeeDTO.setCompanyByCompanyId(employee.getCompanyByCompanyId());
}
employee.getCompanyByCompanyId() -> this is where it throws the Null pointer exception.
The companies table already has the company row that I am associating with employee.
Related
I create application in Spring, which stores albums, musicians and bands. Album can contain multiple bands and musicians. I created association between Album and Band/Musician. Jet I am unable to delete it. I don't want to delete objects, just the association. I tried to send REST PUT request and setting musicians and bands to null on Album site, yet nothing happens:
{
"id": 2,
"title": "Lulu",
"bands": null,
"musicians": null,
"duration": {
"hours": 1,
"minutes": 20,
"seconds": 4
},
"releaseDate": "31/10/2011",
"coverPath": "https://upload.wikimedia.org/wikipedia/en/4/40/Lou_Reed_and_Metallica_-_Lulu.jpg",
"spotifyPath": null
}
I have created following class and method to link Album and Musician, yet I am unable to "unlink" them:
#RestController
public class AlbumMusicianController {
#Autowired
AlbumRepository albumRepository;
#Autowired
MusicianRepository musicianRepository;
#Transactional
#PostMapping("/musician/{musicianId}/album/{albumId}")
public List<Album> associate(#PathVariable Long musicianId, #PathVariable Long albumId) {
Album album = this.albumRepository.findById(albumId).orElseThrow(() -> new MissingResourceException("Album",
"Album", albumId.toString()));
return this.musicianRepository.findById(musicianId).map((musician) -> { musician.getAlbums().add(album);
return this.musicianRepository.save(musician).getAlbums();
}).orElseThrow(() -> new MissingResourceException("Musician", "Musician", musicianId.toString()));
}
}
Would be thankful for any help.
Below are necessary sources.
Album class:
#Entity
#Table(name="album")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Album {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name="title")
private String title;
#ManyToMany(targetEntity = Band.class, mappedBy = "albums")
#JsonSerialize(using = BandsSerializer.class)
private List<Band> bands;
#ManyToMany(targetEntity = Musician.class, mappedBy = "albums")
#JsonSerialize(using = MusiciansSerializer.class)
private List<Musician> musicians;
#Embedded
#Column(name="duration")
private Duration duration;
#Column(name="releasedate")
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd/MM/yyyy", timezone="CET")
private Date releaseDate;
#Column(name="coverpath")
private String coverPath;
#Column(name="spotifypath")
private String spotifyPath;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Duration getDuration() {
return duration;
}
public void setDuration(Duration duration) {
this.duration = duration;
}
public Date getReleaseDate() {
return releaseDate;
}
public void setReleaseDate(Date releaseDate) {
this.releaseDate = releaseDate;
}
public String getCoverPath() {
return coverPath;
}
public void setCoverPath(String coverPath) {
this.coverPath = coverPath;
}
public String getSpotifyPath() {
return spotifyPath;
}
public void setSpotifyPath(String spotifyPath) {
this.spotifyPath = spotifyPath;
}
public List<Band> getBands() {
return bands;
}
public void setBands(List<Band> bands) {
this.bands = bands;
}
public List<Musician> getMusicians() {
return musicians;
}
public void setMusicians(List<Musician> musicians) {
this.musicians = musicians;
}
}
Musician class:
#Entity
#Table(name="musician")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Musician {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name="name")
private String name;
#Column(name="surname")
private String surname;
#Column(name="birthdate")
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd/MM/yyyy", timezone="CET")
private Date birthDate;
#Column(name="picturepath")
private String picturePath;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "album_musician",
joinColumns = #JoinColumn(name = "album_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "musician_id",
referencedColumnName = "id"))
private List<Album> albums;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getPicturePath() {
return picturePath;
}
public void setPicturePath(String picturePath) {
this.picturePath = picturePath;
}
public List<Album> getAlbums() {
return albums;
}
public void setAlbums(List<Album> albums) {
this.albums = albums;
}
}
Band class:
#Entity
#Table(name="band")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Band {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name="name")
private String name;
#Column(name="picturepath")
private String picturePath;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "album_band",
joinColumns = #JoinColumn(name = "album_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "band_id",
referencedColumnName = "id"))
#JsonSerialize(using = AlbumsSerializer.class)
private List<Album> albums;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPicturePath() {
return picturePath;
}
public void setPicturePath(String picturePath) {
this.picturePath = picturePath;
}
public List<Album> getAlbums() {
return albums;
}
public void setAlbums(List<Album> albums) {
this.albums = albums;
}
}
Based on your JSON body I'm going to assume you were sending a PUT request for the Album entity. There were two things that I found missing that got it to work for me after adjusting. I'm not sure if you were avoiding using them for one reason or another.
Cascade rules to cascade changes from Album to its relations.
Proper entity mapping for the join table from Album to its relations.
Not really sure why this was an issue - Hibernate did not seem to throw any exceptions related to this at execution time, but it did not seem to persist things correctly.
Here is an adjusted relation definition for Album's relation to Musician.
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="album_musician", joinColumns = #JoinColumn(name = "musician_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "album_id",
referencedColumnName = "id"))
private List<Musician> musicians;
In this format, I was able to cascade changes from Album to Musician. You will have to do something similar for the Band entity to cascade operations from Album to Band.
I have the following scenario:
I have a Student class and students table.
I have Course class and courses table.
Every student and course have unique ID.
I would like to put a List into the Student class which is mapped by courses IDs.
I have tried a lot of annotations and relations but nothing succeeded
#Entity
#Table(name = "courses")
public class Course {
private long id;
private String name;
public Course() {
}
public Course(String name, int size) {
this.name = name;
this.size = size;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name = "students")
public class Student {
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<Course> courses = new ArrayList<>();
public Student() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
Can you help me hot to achieve that because i am a little newbie into the spring
Use the following when declaring one to many relation
#Column(name="course_id")
private Set<Course> courses;
You need to use OneToMany annotation.
#OneToMany(mappedBy = "students", cascade = CascadeType.ALL)
private List<Course> courses;
You need to give your list a type. For instance
List<Courses> courseList = new ArrayList<>();
When I send a GET request in POSTMAN to get all my child entity (Town) the parent entity (Province) is not shown in the JSON response.
This is my controller.
#RequestMapping(value ="api/v1/town",method = RequestMethod.GET)
public ResponseEntity<List<Town>> getAllTowns() {
List<Town> towns = townService.getAllTowns();
if(towns.isEmpty()) {
return new ResponseEntity<List<Town>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Town>>(towns, HttpStatus.OK);
}
And these are my entities.
Parent Class
#Entity
#Table(name = "PROVINCE")
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "PROVINCE_ID")
private long id;
private String name;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "province", targetEntity = Town.class)
#JsonManagedReference("Province-Town")
private List<Town> towns;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Town> getTowns() {
return towns;
}
public void setTowns(List<Town> towns) {
this.towns = towns;
}
}
Child Class
#Entity
#Table(name = "TOWN")
public class Town {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "TOWN_ID")
private long id;
private String name;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "PROVINCE_ID")
#JsonBackReference("Province-Town")
private Province province;
private long kilometer;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Province getProvince() {
return province;
}
public void setProvince(Province province) {
this.province = province;
}
public long getKilometer() {
return kilometer;
}
public void setKilometer(long kilometer) {
this.kilometer = kilometer;
}
}
The response that I'm getting is like this
{
"id" : 1,
"name" : "Some Town",
"kilometer" : 350
}
What I'm expecting is
{
"id" : 1,
"name" : "Some Town",
"province" : {
//Province data.....
}
"kilometer" : 350
}
I was able to show something like this, but the Objects that I used are not Spring-data-jpa entities, just simple POJOs.
Is there any problem with my Entities? Or is there anything else?
Swap #JsonBackReference and #JsonManagedReference. Basically:
#JsonManagedReference
private Province province;
#JsonBackReference
private List<Town> towns;
I get error:
Invocation of init method failed; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.messagemanager.domain.User column: id (should be mapped with insert="false" update="false")
There are my Entities:
#MappedSuperclass
public abstract class BaseEntity{
#Id
#Column(nullable = false, unique = true, name = "id", insertable = false, updatable = false)
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
#Table(name = "User")
public class User extends BaseEntity implements Serializable{
#Column(name = UserFieldsKey.ID, length = 50, nullable = false)
private String name;
#Column(updatable = false, insertable = false)
#Transient
private List<Message> listMessage = new ArrayList<>();
public static class UserFieldsKey{
public static final String NAME = "name";
}
public User() {
}
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
public List<Message> getListMessage() {
return listMessage;
}
public void setListMessage(List<Message> listMessage) {
this.listMessage = listMessage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name = "Message")
public class Message extends BaseEntity implements Serializable{
#Column(name = MessageFieldsKey.MESSAGE, length = 500, nullable = false)
private String message;
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="user")
private User user;
#Column(name = "id_user")
private Long id_user;
public Long getId_user() {
return id_user;
}
public void setId_user(Long id_user) {
this.id_user = id_user;
}
public static class MessageFieldsKey{
public static final String MESSAGE = "mes";
}
public String getMessage() {
return message;
}
public User getUser() {
return user;
}
public Message() {
}
public Message(String message, User user) {
this.message = message;
this.user = user;
}
public void setMessage(String message) {
this.message = message;
}
public void setUser(User user) {
this.user = user;
}
}
Any ideas?
P.S. thanks a lot!
It looks like that's because you have this:
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="user")
private User user;
which will map to User.id; and in Message you already have an id since you are extending BaseEntity
Issue solved) I mistook in relationship between tables.
Please help me in accessing Employee object in the below code using JAXB annotations. The application was developed in JPA SPRING. We are unable to access sub-object properties i.e, Employee properties
RESOURCE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="resource")
#Entity
#Table(name = "resource")
public class Resource implements java.io.Serializable {
private Integer resourceId;
private String resourceCode;
private String resourceName;
private String resourceNumber;
private Employee employee;
public Resource() {
}
public Resource(Employee employee,String resourceCode, String resourceName,
String resourceNumber
) {
this.employee = employee;
this.resourceCode = resourceCode;
this.resourceName = resourceName;
this.resourceNumber = resourceNumber;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "resource_id", unique = true, nullable = false)
public Integer getResourceId() {
return this.resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
#Column(name = "resource_code")
public String getResourceCode() {
return this.resourceCode;
}
public void setResourceCode(String resourceCode) {
this.resourceCode = resourceCode;
}
#Column(name = "resource_number")
public String getResourceNumber() {
return this.resourceNumber;
}
public void setResourceNumber(String resourceNumber) {
this.resourceNumber = resourceNumber;
}
#Column(name = "resource_name")
public String getResourceName() {
return this.resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
EMPLOYEE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="employee")
#Entity
#Table(name = "employee")
public class Employee implements java.io.Serializable {
private Integer employeeId;
private String employeeCode;
private String employeeName;
private List<Resource> resources = new ArrayList<Resource>(0);
public Employee() {
}
public Employee(String employeeCode, String employeeName,List<Resource> resources
) {
this.employeeCode = employeeCode;
this.employeeName = employeeName;
this.resources = resources;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "employee_id", unique = true, nullable = false)
public Integer getEmployeeId() {
return this.employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
#Column(name = "employee_code")
public String getEmployeeCode() {
return this.employeeCode;
}
public void setEmployeeCode(String employeeCode) {
this.employeeCode = employeeCode;
}
#Column(name = "employee_name")
public String getEmployeeName() {
return this.employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "employee")
public List<Resource> getResources() {
return this.resources;
}
public void setResources(List<Resource> resources) {
this.resources = resources;
}
}
You have to use the FetchType : Eager in RESOURCE CORE FILE of getEmployee() Method. Lazy fetch type is pulling only the parent object. Eager is pulling both.