I am using sprint jpa data to get the list of student and their corresponding courses.
#Entity
#Table(name = "student")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "student_id")
private Integer studentId;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "fname")
private String fname;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "lname")
private String lname;
// #Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email")//if the field contains email address consider using this annotation to enforce field validation
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "email")
private String email;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "username")
private String username;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "password")
private String password;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "student")
#JsonManagedReference
private Set<StudentCourse> studentCourseSet;
Course entity
#Entity
#Table(name = "course")
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "course_id")
private Integer courseId;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 20)
#Column(name = "couse_code")
private String couseCode;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "course_name")
private String courseName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "course")
#JsonManagedReference
private Set<StudentCourse> studentCourseSet;
Student Course
#Entity
#Table(name = "student_course")
public class StudentCourse implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected StudentCoursePK studentCoursePK;
#JoinColumn(name = "course_id", referencedColumnName = "course_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
#JsonBackReference
private Course course;
#JoinColumn(name = "student_id", referencedColumnName = "student_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
#JsonBackReference
private Student student;
And
#Embeddable
public class StudentCoursePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "student_id")
private int studentId;
#Basic(optional = false)
#NotNull
#Column(name = "course_id")
private int courseId;
I have this RestController that return list of student.
#RestController
public class StudentController {
#Autowired
private StudentService studentService;
#Autowired
private CourseService courseService;
#Autowired
StudentRepositoryImpl studentRepositoryCustomImpl;
#RequestMapping(value = "/studentlist")
public Iterable<Student> getStudentList() {
return studentService.getStudentList();
}
The output looks as follow
// 20170929084542
// http://localhost:8080/studentlist
[
{
"studentId": 1,
"fname": "abc",
"lname": "efg",
"email": "a#b.com",
"username": "as",
"password": "as",
"studentCourseSet": [
{
"studentCoursePK": {
"studentId": 1,
"courseId": 4
}
},
{
"studentCoursePK": {
"studentId": 1,
"courseId": 1
}
},
{
"studentCoursePK": {
"studentId": 1,
"courseId": 2
}
},
{
"studentCoursePK": {
"studentId": 1,
"courseId": 3
}
}
]
}
]
How can I include student course name list for the student on the output. I am using spring boot
Related
public class EmployeeEntity {
#Id
#Column(name = "id")
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#Length(min = 2, max = 30)
#Column(name = "name")
private String name;
#Length(min = 2, max = 30)
#Column(name = "last_name")
private String lastName;
#Column(name = "email", nullable = false, unique = true)
#Length(max = 50)
private String email;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id")
private Set<EmployeeRoleEntity> roles;}
This is my Employee class and as you can see inside Employee, I have a set of EmployeeRoleEntity
public class EmployeeRoleEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "role_name")
#Enumerated(EnumType.STRING)
private RoleEntityEnum role;
#ManyToOne
#JoinColumn(name = "employee_id")
#ToString.Exclude
#EqualsAndHashCode.Exclude
private EmployeeEntity employee;
I was trying to filter my employees depends in their role. I created a method like this on my Jpa repository;
List<EmployeeEntity> findByRoles_RoleContainingIgnoreCase( String role);
But it doesn't work and Im so confused to what to do. How can I solve this problem?
Finally I found the answer;
List<EmployeeEntity> findByRoles_Role( RoleEntityEnum role);
This solved my problem. I thought at first the problem was the method but appearently the problem was parameter.
I have Company entity:
#Entity
#Data
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "company_id", nullable = false, unique = true)
private int companyId;
#Column(name = "name", nullable = false, length = 255, unique = true)
private String name;
#JsonIgnore
#OneToMany (mappedBy = "company")
private List<Employee> employeeList;
}
And Employee entity:
#Entity
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id", nullable = false, unique = true)
private int employeeId;
#Column(name = "employee_name", nullable = false)
private String name;
#ManyToOne(optional = false)
#JoinColumn(name = "company_id", nullable = false)
private Company company;
}
I have trouble when I'm mapping EmployeeRequest to Employee object.
This is EmployeeRequest:
#Data
public class EmployeeRequest {
private String name;
private int companyId;
}
As you can see here in request I have companyId which is integer and therefore I have error.
My mapper:
#Component
public class EmployeeMapper {
private Mapper mapper = DozerBeanMapperBuilder.buildDefault();
public Employee transformToEmployeeEntity(EmployeeRequest employeeRequest) {
return mapper.map(employeeRequest, Employee.class);
}
}
I think it makes sense to have an integer as data type in EmployeeRequest. So what is proper way to solve this?
I have entities in my project(based on Spring-Boot + Hibernate):
#Entity
#Table(name = "user_account")
public class UserAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "username")
private String userName;
#NotNull
#Column(name = "first_name")
private String firstName;
#NotNull
#Column(name = "last_name")
private String lastName;
#NotNull
#Column(name = "password")
private String password;
#CreationTimestamp
#Column(name = "birthday")
private LocalDateTime birthday;
#NotNull
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "role", referencedColumnName = "id")
private UserRole role;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount", cascade= CascadeType.ALL)
private Set<RentInfo> rents;
}
and
#Entity
#Table(name = "rent_info")
public class RentInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#ManyToOne(cascade= CascadeType.ALL)
#JoinColumn(name="user_id")
private UserAccount userAccount;
#CreationTimestamp
#Column(name = "start_date")
private LocalDateTime startDate;
#CreationTimestamp
#Column(name = "end_date")
private LocalDateTime endDate;
#Column(name = "status")
private int status;
}
I want to create bi-directional one-to-many relation, when one user can have several rents and when we can select rents by concrete user_id, but something goes wrong
In response I get this:
{
"id": 1,
"userName": "test#mail.loc",
"firstName": "fName",
"lastName": "lName",
"password": "test",
"birthday": "2001-11-03T14:28:14",
"role": {
"name": "CLIENT"
},
"rents": [
{
"userAccount": {
"id": 1,
"userName": "test#mail.loc",
"firstName": "fName",
"lastName": "lName",
"password": "test",
"birthday": "2001-11-03T14:28:14",
"role": {
"name": "CLIENT"
},
"rents": [
{
"userAccount": {
"id": 1,
"userName": "test#mail.loc",
"firstName": "fName",
"lastName": "lName",
"password": "test",
"birthday": "2001-11-03T14:28:14",
"role": {
"name": "CLIENT"
}
.....
And this is unlimited and logically I have out of memory error. How can I fix this? what I'm doing wrong?
You have two solutions :
Use #JsonIgnore on the #ManyToOne
Do NOT serialize your entities. Use DTOs instead and take care while mapping to avoid circular dependencies
You can also use #JsonManagedReference and #JsonBackReference to solve this infinite recursion problem as follows:
#Entity
#Table(name = "user_account")
public class UserAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "username")
private String userName;
#NotNull
#Column(name = "first_name")
private String firstName;
#NotNull
#Column(name = "last_name")
private String lastName;
#NotNull
#Column(name = "password")
private String password;
#CreationTimestamp
#Column(name = "birthday")
private LocalDateTime birthday;
#NotNull
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "role", referencedColumnName = "id")
private UserRole role;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount", cascade= CascadeType.ALL)
#JsonManagedReference
private Set<RentInfo> rents;
}
#Entity
#Table(name = "rent_info")
public class RentInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#ManyToOne(cascade= CascadeType.ALL)
#JoinColumn(name="user_id")
#JsonBackReference
private UserAccount userAccount;
#CreationTimestamp
#Column(name = "start_date")
private LocalDateTime startDate;
#CreationTimestamp
#Column(name = "end_date")
private LocalDateTime endDate;
#Column(name = "status")
private int status;
}
Nevertheless, I would first map your entities to DTOs. However, you might as well need to use #JsonManagedReference and #JsonBackReference in these new DTO classes if you want all data to be available (one way to avoid this infinite recursion problem would be not mapping userAccount in RentInfoDto but you might not want that because you also want to serialize UserAccountDto data).
I need return this Json to my project:
{
"data": {
"id": 1,
"username": "renato",
"name": "Renato",
"email": "asdasd#outlook.com",
"roles": [
{
"id": 1,
"name": "ROLE_USER",
"accessList": [
{
"id_access": 1,
"id_role": {
"id_role": 1,
"name": "ROLE_USER",
"authority": "ROLE_USER"
},
"id_program": {
"id_program": 1,
"code_program": "TEST",
"name": "test"
},
"id_view": {
"id_view": 1,
"code_view": "TEST",
"name": "test"
},
"menuYesNo": true,
"accessYesNo": true,
"saveYesNo": true,
"editYesNo": true,
"deleteYesNo": true
}
]
}
]
}
}
But it return this:
{
"data": {
"id": 1,
"username": "renato",
"name": "Renato",
"email": "asdasd#outlook.com",
"roles": [
{
"id": 1,
"name": "ROLE_USER",
"accessList": [
{
"id_access": 1,
"id_role": {
"id_role": 1,
"name": "ROLE_USER",
"authority": "ROLE_USER"
},
"id_program": {},
"id_view": {},
"menuYesNo": true,
"accessYesNo": true,
"saveYesNo": true,
"editYesNo": true,
"deleteYesNo": true
}
]
}
]
}
}
Only classes AccessModel and RoleModel have bidirectional relationship, exists a relationship unidirectional between ProgramModel and ViewModel with AccessModel.
OBS: I mapped UserModel to UserDTO using ModelMapper. Exists RoleModel inside a UserDTO. RoleModel and AccessModel have an #JsonManagedReference and #JsonBackReference respectively, but ProgramModel and ViewModel not.
#Data
#Entity
#Table(schema = "`SCH`", name = "`USER`")
public class UserModel implements UserDetails {
private static final long serialVersionUID = -2195101536379303067L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(table = "USER", name="`ID_USER`", nullable = true)
private Long id_user;
#Column(table = "USER", name="`USERNAME`", nullable = true, length = 50)
private String username;
#Column(table = "USER", name="`PASSWORD`", nullable = true, length = 255)
private String password;
#Column(table = "USER", name="`NAME`", length = 255)
private String name;
#Column(table = "USER", name="`EMAIL`", length = 255)
private String email;
#Column(table = "USER", name="`DATE_EXPERED`", nullable = true)
private LocalDate dateExpered;
#Column(table = "USER", name="`ACCOUNT_ACTIVE`", nullable = true)
private Boolean accountAtive;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(schema = "`SCH`", name = "`USER_ROLE`" ,
joinColumns = #JoinColumn(
name = "`CD_USER`", referencedColumnName ="`ID_USER`"
),
inverseJoinColumns = #JoinColumn(
name = "`CD_ROLE`", referencedColumnName = "`ID_ROLE`"
))
#JsonBackReference
private Collection<RoleModel> roles;
//METHODS USERDETAILS
}
#Data
#Entity
#Table(schema = "`SCH`", name = "`ROLE`")
public class RoleModel implements GrantedAuthority {
private static final long serialVersionUID = -1320143054659054908L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(table = "ROLE", name = "`ID_ROLE`", nullable = true)
private Long id_role;
#Column(table = "ROLE", name = "`NAME`", nullable = true, length = 255)
private String name;
#JsonBackReference
#OneToMany(cascade = CascadeType.ALL, mappedBy = "id_role", fetch = FetchType.LAZY)
private List<AccessModel> accessList;
}
#Data
#Entity
#Table(schema = "`SCH`", name = "`ACCESS`")
public class AccessModel implements Serializable {
private static final long serialVersionUID = -5590889002302223720L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(table = "ACCESS", name = "`ID_ACCESS`", nullable = true)
private Long id_access;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "`CD_ROLE`")
#JsonManagedReference
private RoleModel id_role;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "`CD_PROGRAM`")
private ProgramModel id_program;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "`CD_VIEW`")
private ViewModel id_view;
#Column(table = "ACCESS", name = "`MENU_YES_NO`", nullable = true)
private Boolean menuYesNo;
#Column(table = "ACCESS", name = "`ACCESS_YES_NO`", nullable = true)
private Boolean accessYesNo;
#Column(table = "ACCESS", name = "`SAVE_YES_NO`", nullable = true)
private Boolean saveYesNo;
#Column(table = "ACCESS", name = "`EDIT_YES_NO`", nullable = true)
private Boolean editYesNo;
#Column(table = "ACCESS", name = "`DELETE_YES_NO`", nullable = true)
private Boolean deleteYesNo;
}
#Entity
#Table(name = "`PROGRAM`", schema = "`SCH`")
public class ProgramModel implements Serializable {
private static final long serialVersionUID = -726159076909575803L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(table = "PROGRAM", name = "`ID_PROGRAM`", nullable = true)
private Long id_program;
#Column(table = "PROGRAM", name = "`CODE_PROGRAM`", nullable = true)
private String code_program;
#Column(table = "PROGRAM", name = "`NAME`", nullable = true)
private String name;
#Column(table = "PROGRAM", name = "`ACTIVE`", nullable = true)
private Boolean active;
}
#Entity
#Table(name = "`VIEW`", schema = "`SCH`")
public class ViewModel implements Serializable {
private static final long serialVersionUID = 3900486010030569933L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(table = "VIEW", name = "`ID_VIEW`", nullable = true)
private Long id_view;
#Column(table = "VIEW", name = "`CODE_VIEW`", nullable = true)
private String code_view;
#Column(table = "VIEW", name = "`NAME`", nullable = true)
private String name;
#Column(table = "VIEW", name = "`ACTIVE`", nullable = true)
private Boolean active;
}
I forgot to put #Data in ProgramModel and ViewModel.
I'm starting with hibernate and I having some difficulties to build a easy
relationship of tables
, hibernate throw nested exception is org.hibernate.MappingException: Unable to find column with logical name: USERNAME in org.hibernate.mapping.Table(USER_FILESYSTEM) and its related supertables and secondary tables
I have this model
USER--1---N-->USER_FILE_SYSTEM--1--N-->USER_FS_THUMBS
All column name on DB squema are OK the column username" exists on table USER_FILESYSTEM
and table user
Table Users
#Entity
#Table(name = "USERS")
public class Users implements Serializable {
#Id
#Column(name = "USERNAME", nullable = false, length = 15)
private String username;
#Column(name = "PASSWORD", nullable = false, length = 64)
private String password;
#Column(name = "FIRSTNAME", length = 32)
private String firstname;
#Column(name = "LASTNAME", length = 32)
private String lastname;
#Column(name = "EMAIL", nullable = false, length = 60)
private String email;
#Column(name = "TELEPHONE", length = 50)
private String telephone;
#OneToOne(cascade = CascadeType.ALL)
#JoinTable(name = "USER_ROLE",
joinColumns = {
#JoinColumn(name = "USERNAME_ID", referencedColumnName = "USERNAME")},
inverseJoinColumns = {
#JoinColumn(name = "ROL_ID", referencedColumnName = "ROL")}
)
private Rol role;
#OneToMany(
fetch = FetchType.EAGER, mappedBy = "username"
)
private Set<UserFileSystem> fileSystem;
Table UserFileSystem
#Entity
#Table(name = "USER_FILESYSTEM")
public class UserFileSystem implements Serializable {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USERNAME", nullable = false)
private Users username;
#Id
#Column(name = "SERVICE_ID", nullable = false, length = 10)
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer serviceId;
#Id
#Column(name = "SERVICE_FOLDER", nullable = false, length = 64)
private String serviceFolder;
#Column(name = "PROTOCOL", length = 20)
private String protocol;
#Column(name = "PARAMS", length = 512)
private String params;
#OneToMany(
fetch = FetchType.LAZY, mappedBy = "userFileSystemThumbsPK"
)
private Set<UserFileSystemThumbs> fileSystemThumbs;
Table UserFileSystemThumbs
#Entity
#Table(name = "USER_FS_THUMBS")
public class UserFileSystemThumbs implements Serializable {
#EmbeddedId
private UserFileSystemThumbsPK userFileSystemThumbsPK;
#Column(name = "SERVICE_URL", nullable = false)
private String serviceUrl;
#Column(name = "CONTENT", nullable = false)
private byte[] content;
#Column(name = "MIME_TYPE", nullable = false)
private String mimeType;
Primary key entity UserFileSystemThumbs
#Embeddable
public class UserFileSystemThumbsPK implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "USERNAME", nullable = false, referencedColumnName = "USERNAME"),
#JoinColumn(name = "SERVICE_ID", nullable = false, referencedColumnName = "SERVICE_ID")
})
private UserFileSystem userFileSystem;
#Column(name = "SERVICE_URL_HASH", nullable = false)
private String serviceUrlHash;
Constructor equals hash....
the problem I think that UserFileSystemThumbsPK USERNAME column do reference to UserFileSystem but in this table the column USERNAME is provided by users.
Solution by OP.
I changed
#Entity
#Table(name = "USER_FILESYSTEM")
public class UserFileSystem implements Serializable {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USERNAME", nullable = false)
private Users username;
#Id
#Column(name = "SERVICE_ID", nullable = false, length = 10)
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer serviceId;
}
for this
#Entity
#Table(name = "USER_FILESYSTEM")
public class UserFileSystem implements Serializable {
#EmbeddedId
private UserFileSystemID userFSID;
}
and I created the object UserFileSystemID with 2 values of PK
It's working like a champ!