I tried to create a query that returns different columns from two tables, and I want the query columns to be mapped to the user definition class.
my Student Model :
package com.example.demo.models;
import javax.persistence.*;
import java.util.List;
#Entity
#Table
public class Students {
public Students() {
}
public Students(String firstName, String lastName, String age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
#Column
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String age;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinTable(name = "Student_Course",
joinColumns = #JoinColumn(name="studentID"),
inverseJoinColumns = #JoinColumn(name="courseID"))
private List<Course> courses;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
my Course Model :
package com.example.demo.models;
import javax.persistence.*;
import java.util.List;
#Entity
#Table
public class Course {
public Course() {
}
public Course(String courseName, String unitCount) {
this.courseName = courseName;
this.unitCount = unitCount;
}
#Column
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "CourseName")
private String courseName;
#Column
private String unitCount;
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinTable(name = "Student_Course",
joinColumns = #JoinColumn(name="courseID"),
inverseJoinColumns = #JoinColumn(name="studentID"))
private List<Students> students;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "teacherID")
private Teachers teachers;
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getUnitCount() {
return unitCount;
}
public void setUnitCount(String unitCount) {
this.unitCount = unitCount;
}
public List<Students> getStudents() {
return students;
}
public void setStudents(List<Students> students) {
this.students = students;
}
public Teachers getTeachers() {
return teachers;
}
public void setTeachers(Teachers teachers) {
this.teachers = teachers;
}
}
my Query in Service Layer:
#Transactional
public List<StudentInfo> getStudentInfo(){
Session session = sf.openSession();
Query hql = session.createQuery("select std.firstName, std.lastName, c.courseName from Students std join std.courses c");
var data = hql.list();
session.close();
return data;
}
and i want map query columns to this simple class :
package com.example.demo.ViewModels;
public class StudentInfo {
private String firstName;
private String lastName;
private String courseName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
}
and in finally..
my controller Class :
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView Index() {
List<StudentInfo> data = studentRepository.getAll();
return new ModelAndView("indexView", "data", data);
}
notice : i`m using thymeleaf in this project.
please help me.
thanks.:D
If you use Spring Data JPA you should be able to do it in the repository using the #Query annotation:
#Query(value = "SELECT new com.path.to.StudentInfo(std.firstName, " +
"std.lastName, c.courseName) " +
"FROM Students std join std.courses c"
List<StudentInfo> getAllStudentInfo();
Make sure you have an all-args constructor in StudentInfo though.
If you use Hibernate, it's almost the same:
entityManager.createQuery("SELECT new com.path.to.StudentInfo(std.firstName, " +
"std.lastName, c.courseName) " +
"FROM Students std join std.courses c",
StudentInfo.class)
Edit: I have concerns about whether it's supposed to work when using join, but give it a try regardless.
Related
I have an issue in joining two tables column. I have two entities Status Report and Employee. and I want the data of employee inside StatusReport.
package com.sl.ems.models;
import javax.persistence.*;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
#Entity
#Table(name="statusreport")
public class StatusReport {
private BigInteger COMPLIANCEID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger STATUSRPTID;
private BigInteger EMPID;
private String COMMENTS;
private Date CREATEDDATE;
private BigInteger DEPARTMENT_ID;
#OneToOne
#JoinTable(name = "Employees")
#JoinColumn(name = "EMPID")
private Employees employee;
public StatusReport(){
}
public StatusReport(BigInteger COMPLIANCEID,BigInteger EMPID,
String COMMENTS,Date CREATEDDATE,BigInteger DEPARTMENT_ID){
this.COMPLIANCEID=COMPLIANCEID;
this.EMPID=EMPID;
this.COMMENTS=COMMENTS;
this.CREATEDDATE=CREATEDDATE;
this.DEPARTMENT_ID=DEPARTMENT_ID;
}
public BigInteger getCOMPLIANCEID() {
return COMPLIANCEID;
}
public void setCOMPLIANCEID(BigInteger COMPLIANCEID) {
this.COMPLIANCEID = COMPLIANCEID;
}
public BigInteger getSTATUSRPTID() {
return STATUSRPTID;
}
public void setSTATUSRPTID(BigInteger STATUSRPTID) {
this.STATUSRPTID = STATUSRPTID;
}
public BigInteger getEMPID() {
return EMPID;
}
public void setEMPID(BigInteger EMPID) {
this.EMPID = EMPID;
}
public String getCOMMENTS() {
return COMMENTS;
}
public void setCOMMENTS(String COMMENTS) {
this.COMMENTS = COMMENTS;
}
public Date getCREATEDDATE() {
return CREATEDDATE;
}
public void setCREATEDDATE(Date CREATEDDATE) {
this.CREATEDDATE = CREATEDDATE;
}
public BigInteger getDEPARTMENT_ID() {
return DEPARTMENT_ID;
}
public void setDEPARTMENT_ID(BigInteger DEPARTMENT_ID) {
this.DEPARTMENT_ID = DEPARTMENT_ID;
}
public Employees getEmployee() {
return employee;
}
public void setEmployee(Employees employee) {
this.employee = employee;
}
}
Another class is the employee:
package com.sl.ems.models;
import com.sl.ems.utils.Utils;
import javax.persistence.*;
import java.math.BigInteger;
import java.util.Date;
#Entity
public class Employees {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger EMPID;
private String FIRSTNAME;
private String LASTNAME;
private Date DOB;
private String EMAIL;
private BigInteger DEPARTMENT_ID;
#OneToOne
#JoinTable(name = "Department")
#JoinColumn(name = "DEPARTMENT_ID")
private Department department;
public Employees(){
}
public Employees(String FIRSTNAME,String LASTNAME,Date DOB,String EMAIL,BigInteger DEPARTMENT_ID){
this.FIRSTNAME=FIRSTNAME;
this.LASTNAME=LASTNAME;
this.DOB=DOB;
this.EMAIL=EMAIL;
this.DEPARTMENT_ID=DEPARTMENT_ID;
}
public BigInteger getEMPID() {
return EMPID;
}
public void setEMPID(BigInteger EMPID) {
this.EMPID = EMPID;
}
public String getFIRSTNAME() {
return FIRSTNAME;
}
public void setFIRSTNAME(String FIRSTNAME) {
this.FIRSTNAME = FIRSTNAME;
}
public String getLASTNAME() {
return LASTNAME;
}
public void setLASTNAME(String LASTNAME) {
this.LASTNAME = LASTNAME;
}
public Date getDOB() {
return DOB;
}
public void setDOB(Date DOB) {
this.DOB = DOB;
}
public String getEMAIL() {
return EMAIL;
}
public void setEMAIL(String EMAIL) {
this.EMAIL = EMAIL;
}
public BigInteger getDEPARTMENT_ID() {
return DEPARTMENT_ID;
}
public void setDEPARTMENT_ID(BigInteger DEPARTMENT_ID) {
this.DEPARTMENT_ID = DEPARTMENT_ID;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
As you can see employee entity itself have some other joins on other tables. Which is a deparment table.
package com.sl.ems.models;
import javax.persistence.*;
import java.math.BigInteger;
#Entity
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger DEPARTMENT_ID;
private String DEPARTMENT_NM;
public Department(){
}
public Department(String DEPARTMENT_NM){
this.DEPARTMENT_NM=DEPARTMENT_NM;
}
public BigInteger getDEPARTMENT_ID() {
return DEPARTMENT_ID;
}
public void setDEPARTMENT_ID(BigInteger DEPARTMENT_ID) {
this.DEPARTMENT_ID = DEPARTMENT_ID;
}
public String getDEPARTMENT_NM() {
return DEPARTMENT_NM;
}
public void setDEPARTMENT_NM(String DEPARTMENT_NM) {
this.DEPARTMENT_NM = DEPARTMENT_NM;
}
}
When I join Status Report with Employee I get Sql exception. But strangly when I remove join of Department in Employee entity table then I get the result.
Can someone please help if I am missing anything?
Looks like your mapping is not correct. Also verify you have a EMPID column.
You don't need to use the #JoinTable annotation in your case.
StatusReport - removed private BigInteger EMPID; as it is ued n joining
#Entity
#Table(name="statusreport")
public class StatusReport {
private BigInteger COMPLIANCEID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger STATUSRPTID;
private String COMMENTS;
private Date CREATEDDATE;
private BigInteger DEPARTMENT_ID;
#OneToOne
#JoinColumn(name = "EMPID")
private Employees employee;
//others methods
Employee - removed private BigInteger DEPARTMENT_ID; as it is ued n joining
#Entity
public class Employees {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger EMPID;
private String FIRSTNAME;
private String LASTNAME;
private Date DOB;
private String EMAIL;
#OneToOne
#JoinColumn(name = "DEPARTMENT_ID")
private Department department;
Well taking help from above post. I made few other changes in my code. As I could not manage to remove the field completely from my entity class so I made it Transient and set its property from the join column object method. So my class are as follows.
Employee class is as follows.
package com.sl.ems.models;
import javax.persistence.*;
import java.math.BigInteger;
import java.util.Date;
#Entity
public class Employees {
/**
Author: Puneet Kumar Bahuguna
Year: DEC 2020
Project: SimplyLearn EMS
Description: This Entity class mapped to the employees table in the database.
**/
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger EMPID;
private String FIRSTNAME;
private String LASTNAME;
private Date DOB;
private String EMAIL;
#Transient
private BigInteger DEPARTMENT_ID;
#OneToOne
#JoinColumn(name = "DEPARTMENT_ID")
private Department department;
public Employees(){
}
public Employees(BigInteger EMPID){
this.EMPID=EMPID;
}
public Employees(String FIRSTNAME,String LASTNAME,Date DOB,String EMAIL,Department department){
this.FIRSTNAME=FIRSTNAME;
this.LASTNAME=LASTNAME;
this.DOB=DOB;
this.EMAIL=EMAIL;
this.department=department;
}
public BigInteger getEMPID() {
return EMPID;
}
public void setEMPID(BigInteger EMPID) {
this.EMPID = EMPID;
}
public String getFIRSTNAME() {
return FIRSTNAME;
}
public void setFIRSTNAME(String FIRSTNAME) {
this.FIRSTNAME = FIRSTNAME;
}
public String getLASTNAME() {
return LASTNAME;
}
public void setLASTNAME(String LASTNAME) {
this.LASTNAME = LASTNAME;
}
public Date getDOB() {
return DOB;
}
public void setDOB(Date DOB) {
this.DOB = DOB;
}
public String getEMAIL() {
return EMAIL;
}
public void setEMAIL(String EMAIL) {
this.EMAIL = EMAIL;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public void setDEPARTMENT_ID(BigInteger DEPARTMENT_ID) {
this.DEPARTMENT_ID = DEPARTMENT_ID;
}
public BigInteger getDEPARTMENT_ID() {
return DEPARTMENT_ID;
}
}
StatusReport class is as follows.
package com.sl.ems.models;
import javax.persistence.*;
import java.math.BigInteger;
import java.util.Date;
#Entity
#Table(name="statusreport")
public class StatusReport {
/**
Author: Puneet Kumar Bahuguna
Year: DEC 2020
Project: SimplyLearn EMS
Description: This Entity class mapped to the statusreport table in the database.
**/
private BigInteger COMPLIANCEID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigInteger STATUSRPTID;
private String COMMENTS;
private Date CREATEDDATE;
private BigInteger DEPARTMENT_ID;
#Transient
private BigInteger EMPID;
#OneToOne
#JoinColumn(name = "EMPID")
private Employees employee;
public StatusReport(){
}
public StatusReport(String COMMENTS,Date CREATEDDATE){
}
public StatusReport(BigInteger COMPLIANCEID,String COMMENTS,Date CREATEDDATE,
BigInteger DEPARTMENT_ID,Employees employee){
this.COMPLIANCEID=COMPLIANCEID;
this.COMMENTS=COMMENTS;
this.CREATEDDATE=CREATEDDATE;
this.DEPARTMENT_ID=DEPARTMENT_ID;
this.employee=employee;
}
public BigInteger getCOMPLIANCEID() {
return COMPLIANCEID;
}
public void setCOMPLIANCEID(BigInteger COMPLIANCEID) {
this.COMPLIANCEID = COMPLIANCEID;
}
public void setEMPID(BigInteger EMPID) {
this.EMPID = EMPID;
}
public BigInteger getEMPID() {
return EMPID;
}
public BigInteger getSTATUSRPTID() {
return STATUSRPTID;
}
public void setSTATUSRPTID(BigInteger STATUSRPTID) {
this.STATUSRPTID = STATUSRPTID;
}
public String getCOMMENTS() {
return COMMENTS;
}
public void setCOMMENTS(String COMMENTS) {
this.COMMENTS = COMMENTS;
}
public Date getCREATEDDATE() {
return CREATEDDATE;
}
public void setCREATEDDATE(Date CREATEDDATE) {
this.CREATEDDATE = CREATEDDATE;
}
public BigInteger getDEPARTMENT_ID() {
return DEPARTMENT_ID;
}
public void setDEPARTMENT_ID(BigInteger DEPARTMENT_ID) {
this.DEPARTMENT_ID = DEPARTMENT_ID;
}
public Employees getEmployee() {
return employee;
}
public void setEmployee(Employees employee) {
this.employee = employee;
}
}
Please also note for example while you are saving a StatusReport object by using save method of jpa you will have to set the EMPID through getEmployee().getEMPID()
I know there are numerous posts about this problem and I've tried their solutions yet still couldn't solve my problem. I've started a Spring Boot application and it is connected to a postgesql db. I have two classes named Student and Course. I want to create a ManyToMany relation between them. When I run the application it creates the tables as I wanted. And also if I insert a record for course_student table, I can display the courses that a student takes. But I can append a new course for a student nothing happens.
Student class
package com.example.demo.models;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "students")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
#ManyToMany(
fetch = FetchType.LAZY,
cascade = {
CascadeType.ALL,
},
mappedBy = "students"
)
private Set<Course> courses = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
Course class
package com.example.demo.models;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "courses")
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#ManyToMany(
fetch = FetchType.LAZY,
cascade = {
CascadeType.ALL,
}
)
#JoinTable(
name = "course_student",
joinColumns = { #JoinColumn(name = "course_id") },
inverseJoinColumns = { #JoinColumn(name = "student_id") }
)
private Set<Student> students = new HashSet<>();
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 Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
IStudentRepository
package com.example.demo.repositories;
import com.example.demo.models.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface IStudentRepository extends JpaRepository<Student, Long> {
}
SqlStudentService class
package com.example.demo.services;
import com.example.demo.models.Course;
import com.example.demo.models.Student;
import com.example.demo.repositories.IStudentRepository;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
#Service("SqlStudentService")
public class SqlStudentService implements IStudentService {
private final IStudentRepository studentRepository;
public SqlStudentService(IStudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
public List<Student> getStudents() {
return studentRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
}
public Student getStudentById(Long id) {
return studentRepository.findById(id).orElse(null);
}
public Student insertStudent(Student student) {
return studentRepository.save(student);
}
public Student updateStudent(Long id, Student student) {
Student oldStudent = getStudentById(id);
if (oldStudent != null) {
oldStudent.setFirstName(student.getFirstName());
oldStudent.setLastName(student.getLastName());
return studentRepository.save(oldStudent);
}
return null;
}
public void deleteStudentById(Long id) {
studentRepository.deleteById(id);
}
public void addStudentToCourse(Course course, Long studentId) {
Student student = getStudentById(studentId);
if (student != null) {
student.getCourses().add(course);
studentRepository.save(student);
}
}
}
All of other functions in SqlStudentService class work properly but addStudentToCourse method does not. I've return the Student object after the student.getCourses().add(course); line. The course added successfully. But it is not added to that record to course_student table. Do you have any idea what I am missing? Thank you so much.
#ManyToMany
#JoinTable(name = "course_student", joinColumns = { #JoinColumn(name = "course_id_fk", referencedColumnName ="course_id_pk") },
inverseJoinColumns = { #JoinColumn(name =
"student_id_fk",referencedColumnName="student_id_pk") })
private Set<Student> students;
You don't have to use Cascading Type =All and fetch type as it is lazy default
I have two tables: authors and books
Author:
#Entity
#Table (name="authors")
public class Author implements java.io.Serializable {
private Integer id;
private String name;
private String lastName;
/*book list*/
private Set<Book> books= new HashSet<Book>(0);
public Author() {
}
public Author(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public Author(String name, String lastName, Set<Book> books) {
this.name = name;
this.lastName = lastName;
this.books = books;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "AUTHOR_ID", unique = true, nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "AUTHOR_NAME", unique = true, nullable = false, length = 10)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "AUTHOR_LASTNAME", unique = true, nullable = false, length = 10)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
}
Book:
import javax.persistence.*;
#Entity
#Table(name = "books")
public class Book implements java.io.Serializable {
private Integer id;
private String name;
private Author author;
public Book() {
}
public Book(String name) {
this.name = name;
}
public Book(String name, Author author) {
this.name = name;
this.author = author;
}
#Id
#Column(name = "BOOK_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "BOOK_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "AUTHOR_ID",nullable = false)
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
In my book's table I have field with id author. How can I get all books from one author? How Can I solve it?
Must I use HQL or other methods? I am beginner in this.
first you need to the mapping between two entities.
Author class
#OneToMany(mappedBy="author")
private Set<Book> books= new HashSet<Book>(0);
Book class
#ManyToOne
private Author author;
after that you can use a simple criteria query to retrieve the relevant records.
I wont help you with the code here but the logic..
The very first thing you need to do is build a relationship between Author and Books using the annotations #OneToMany or #ManyToOne depending on your structure.
Next use the Author Class Object to retrive the list of Books.
I'm trying to use JPA for the first time in a project. Most of my entities are working fine, but I am having trouble with one which is part of a Joined Inheritance Strategy.The entities are also being serialised by Jackson so they also have Json annotations.
The parent "User" class:
(Edit: added "Type" field)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.WRAPPER_OBJECT)
#JsonTypeName("user")
#JsonSubTypes({
#JsonSubTypes.Type(name="customer", value=Customer.class),
#JsonSubTypes.Type(name="employee", value=Employee.class)})
#Entity(name = "User")
#Table(name="user")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name="type",discriminatorType = DiscriminatorType.INTEGER)
#NamedQuery(name="User.all",query = "select u from User u")
public abstract class User {
#Id
private String username;
#Column(name = "type",nullable = false)
private int type;
public User(){
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public abstract Set<Order> getOrders();
}
A Child "Employee"
#JsonTypeName("employee")
#Entity(name="Employee")
#Table(name="employee")
#PrimaryKeyJoinColumn(name = "username",referencedColumnName = "username")
#DiscriminatorValue("1")
#NamedQuery(name = "Employee.all",query = "select e from Employee e")
public class Employee extends User implements Serializable{
private String username;
private String firstName;
private String lastName;
private String email;
#Convert(converter = LocalDatePersistenceConverter.class)
private LocalDate dateStarted;
#Convert(converter = LocalDatePersistenceConverter.class)
private LocalDate dateEnded;
#OneToMany(mappedBy = "employee",targetEntity = Order.class,fetch = FetchType.EAGER,cascade = CascadeType.PERSIST)
#JsonIgnore
private Set<Order> orders = new HashSet<>();
public Employee() {
}
#Override
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
public void addOrder(Order order){
orders.add(order);
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
public String getDateStarted() {
if(dateStarted != null)
return dateStarted.toString();
else return null;
}
public void setDateStarted(LocalDate dateStarted) {
this.dateStarted = dateStarted;
}
public String getDateEnded() {
if(dateEnded != null)
return dateEnded.toString();
else return null;
}
public void setDateEnded(LocalDate dateEnded) {
this.dateEnded = dateEnded;
}
#Override
public String toString(){
return getUsername();
}
}
And a child "Customer":
(Edit: removed #Id field)
#JsonTypeName("customer")
#Entity(name="Customer")
#Table(name="customer")
#PrimaryKeyJoinColumn(name = "username",referencedColumnName = "username")
#DiscriminatorValue("2")
#NamedQueries({
#NamedQuery(name="Customer.all",query = "select c from Customer c")
})
public class Customer extends User implements Serializable{
public enum VIP_TYPE {NORMAL,SILVER,GOLD,DIAMOND}
#Transient
private static final int SILVER_THRESHOLD = 1000;
#Transient
private static final int GOLD_THRESHOLD = 2000;
#Transient
private static final int DIAMOND_THRESHOLD = 3000;
private String firstName;
private String lastName;
private String email;
private String address;
private String postcode;
private String mobileNumber;
private String homeNumber;
#Convert(converter = VipTypeConverter.class)
private VIP_TYPE vipGroup;
private String discount;
#OneToMany(mappedBy = "customer",targetEntity = Order.class,fetch=FetchType.EAGER,cascade = CascadeType.ALL)
#JsonIgnore
private Set<Order> orders = new HashSet<>();
public Customer() {
}
#Override
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
public void addOrder(final Order order){
orders.add(order);
updateVipGroup();
}
private void updateVipGroup() {
int sum = orders.stream().map(Order::getPayment).distinct().mapToInt(p->p.getAmmount()).sum();
if(sum > DIAMOND_THRESHOLD){
vipGroup = VIP_TYPE.DIAMOND;
return;
}
if(sum > GOLD_THRESHOLD){
vipGroup = VIP_TYPE.GOLD;
return;
}
if(sum > SILVER_THRESHOLD){
vipGroup = VIP_TYPE.SILVER;
return;
}
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setEmail(String email) {
this.email = email;
}
public void setAddress(String address) {
this.address = address;
}
public void setDiscount(String discount) {
this.discount = discount;
}
public void setVipGroup(VIP_TYPE vipGroup) {
this.vipGroup = vipGroup;
}
public void setHomeNumber(String homeNumber) {
this.homeNumber = homeNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
public String getDiscount() {
return discount;
}
public VIP_TYPE getVipGroup() {
return vipGroup;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
public String getAddress() {
return address;
}
public String getPostcode() {
return postcode;
}
public String getMobileNumber() {
return mobileNumber;
}
public String getHomeNumber() {
return homeNumber;
}
}
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="local" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/cod</jta-data-source>
<class>com.technicalpioneers.cod.user.Customer</class>
<class>com.technicalpioneers.cod.user.Employee</class>
<class>com.technicalpioneers.cod.user.User</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
Everything to do with "employee" works file, I can use the named query Employee.all to find all the employees in the database.
However, If I try to retrieve any customers I get errors. If I try to run the named query Customer.all I get:
java.lang.IllegalArgumentException: NamedQuery of name: Customer.all not found.
If I try to use EntityManager's find() method to find a particular customer I get:
javax.servlet.ServletException: Exception [EclipseLink-43] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing class for indicator field value [2] of type [class java.lang.Integer].
Descriptor: RelationalDescriptor(com.technicalpioneers.cod.user.User --> [DatabaseTable(user)])
I don't understand why the Customer entity is not being found by JPA. I've checked the user table and the "type" column is there with correct numbers, and #DescriminatorValue is set correctly. It's almost like the annotations are being ignored?
Have done many clean rebuilds and redeploys too. Any help would be very much appreciated!
I found this eventually. https://bugs.eclipse.org/bugs/show_bug.cgi?id=429992
It turns out EclipseLink will silently ignore entities with lambda expressions! Very annoying for it to not be at least mentioned in logs!
Thanks to everyone who took the time!
I have a ManyToMany relationship between person that I'm trying to describe with Hibernate annotations. I have also created a test for this but the problem is that the relationship isn't saved. Please help me find where I did wrong!
Entity:
#Entity(name = "person")
#Table(appliesTo = "person", indexes = {
#org.hibernate.annotations.Index(name = "ix_uuid", columnNames = {"uuid"}),
#org.hibernate.annotations.Index(name = "ix_facebookId", columnNames = {"facebookId"})
})
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
private String uuid;
private String firstName;
private String lastName;
private String facebookId;
private String email;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "person_friend",
joinColumns = #JoinColumn(name = "person_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "friend_id", referencedColumnName = "id")
)
private Set<Person> persons = new HashSet<Person>();
#ManyToMany(mappedBy = "persons", cascade = CascadeType.ALL)
private Set<Person> friends = new HashSet<Person>();
public Person(String uuid, String firstName, String lastName, String facebookId, String email) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.facebookId = facebookId;
this.email = email;
}
public Person() {
// Hibernate
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFacebookId() {
return facebookId;
}
public void setFacebookId(String facebookId) {
this.facebookId = facebookId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void addFriend(Person person){
if(!getFriends().contains(person)){
getFriends().add(person);
person.getPersons().add(this);
}
}
public void becomeFriendOf(Person person) {
if(!getPersons().contains(person)){
getPersons().add(person);
person.getFriends().add(this);
}
}
public Set<Person> getFriends() {
return friends;
}
public void setFriends(Set<Person> friends) {
this.friends = friends;
}
public Set<Person> getPersons() {
return persons;
}
public void setPersons(Set<Person> persons) {
this.persons = persons;
}
#Override
public String toString() {
return "Person{" +
"id=" + id +
", uuid='" + uuid + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", facebookId='" + facebookId + '\'' +
", email='" + email + '\'' +
'}';
}
}
PersonDao:
#Repository("personDao")
public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao {
#Autowired
public PersonDaoImpl(SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);
}
#Override
public void save(Person person) {
getSession().save(person);
}
#Override
public Person getPerson(Long id) {
return (Person) getSession().get(Person.class, id);
}
#Override
public void saveFriendship(Friendship friendship) {
getSession().save(friendship);
}
}
Test:
#Test(groups = {"integration"})
#ContextConfiguration(locations = {"classpath:applicationContext-test.xml" })
public class PersonDaoImplTest extends AbstractTestNGSpringContextTests {
#Autowired
private PersonDao target;
#Test
public void loadDatabaseWithSomeInitialValues(){
System.out.println(applicationContext.toString());
Person person = new Person("12345abcde","test","test2","test.test", "test.test#gmail.com");
Person person2 = new Person("4567abcde","fest","fest","fest.fest", "fest.fest#gmail.com");
Person person3 = new Person("89105abcde","best","best","best.best", "best.best#gmail.com");
person.addFriend(person2);
person.addFriend(person3);
person2.becomeFriendOf(person);
person3.becomeFriendOf(person);
target.save(person);
}
}
}
As stated the persons are saved in the person table but not the relationship in the person_friend table. Why?
Perhaps it has something to do with transaction boundaries. Try to make your test method #Transactional.