I have following code:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#NotNull
#Column(name = "LOGIN", unique = true)
private String login;
#Column(name = "PASSWORD")
private String password;
#Column(name = "ROLE")
private UserRole role;
#Column(name = "E_MAIL", unique = true)
private String email;
#Convert(converter = UserStrategyConverter.class)
#Column(name = "STRATEGY")
private UserStrategy userStrategy;
#Column(name = "SUBSCRIPTION")
private Boolean subscription;
#Column(name = "MONEY")
private BigDecimal money;
My problem: When I put this object from postman in json:
{
"firstName": "Daniel",
"lastName": "xxx",
"password": "daniel",
"role": "ROLE_USER",
"email": "test#test.pl",
"subscription": false,
"money": "1200"
}
It create object in entity. Problem is because I can multiply this object again and again instead of unique = true in columns (email and login). Can anyone explain me why?
Hibernate will take into account the constraint unique = true only at the time of schema generation.
During schema generation the following constraint will be added:
alter table User
add constraint UK_u31e1frmjp9mxf8k8tmp990i unique (email)
If you do not use the schema generation there is no sense of using unique = true.
Related
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 have the following entity in SpringBoot and I would like to create a new entity which has the userID of the registered user and the name of the registered/logged in user as instance fields/table columns.
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="User")
public class WebUser {
#Id
#GeneratedValue
private Long userID;
#NonNull
private String name;
#NonNull
private String email;
#NonNull
private String password;
}
How would I go about doing this using a form in SpringBoot and JPA entity? I am struggling, I tried to create a form with hidden input fields using #OneToMany annotation but the userID and name were null.
Thanks for any help
Frist of all you Should define table column names using #Column(name = "COLUMN_NAME") and assume your new entity name LogUser.
LogUser
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="LogUser")
public class LogUser{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", nullable = false)
private WebUser webUser;
#Column(name = "NAME", nullable = false)
private String name;
}
WebUser
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name="User")
public class WebUser {
#Id
#GeneratedValue
#Column(name = "USER_ID")
private Long userID;
#Column(name = "NAME", nullable = false)
private String name;
#Column(name = "EMAIL", nullable = false)
private String email;
#Column(name = "PASSWORD", nullable = false)
private String password;
#OneToMany(mappedBy = "webUser")
private Set<LogUser> logUsers;
}
I have two entities. Customer which is mapped in one to many relation with the CustomerDepartment. CustomerDepartment table has a column to store customer Id.
I want to map them in such a way that Customer Object store a list of Customer Department, and the Customer Department stores the id of the customer it belongs to.
The code that is working compels me to send the all the customer details while creating or updating a customer Department.
Is there a way I can only send the id of the customer and it maps itself?
I have tried changing from -
#JsonBackReference
#ManyToOne
#JoinColumn(name = "customer_no", nullable = false)
private Customer customer;
to this -
#JsonBackReference
#ManyToOne(targetEntity = Customer.class)
#JoinColumn(name = "customer_no", nullable = false)
private Integer customer;
which gives me the requestbody I want but it does not work giving the following error -
2019-08-03 04:59:08 ERROR CustomerController:72 - org.springframework.orm.jpa.JpaSystemException: Error accessing field [private java.lang.Integer com.enquero.pulse.entity.Customer.customerNo] by reflection for persistent property [com.enquero.pulse.entity.Customer#customerNo] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.Integer com.enquero.pulse.entity.Customer.customerNo] by reflection for persistent property [com.enquero.pulse.entity.Customer#customerNo] : 1
Working Code:
Customer:-
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#DynamicUpdate
#Entity
#Table(name = "customer")
public class Customer extends Auditable<Integer>{
#Id
#Column(name = "customer_no")
private Integer customerNo;
#NotBlank
#Column(name = "customer_name")
private String customerName;
#Column(name = "industry")
private String industry;
#Column(name = "country")
private String country;
#Column(name = "state")
private String state;
#Column(name = "city")
private String city;
#Column(name = "postal_code")
private String postalCode;
#Column(name = "address_line1")
private String addressLine1;
#Column(name = "address_line2")
private String addressLine2;
#Column(name = "address_line3")
private String addressLine3;
#Column(name = "payment_term")
private String paymentTerm;
#Column(name = "customer_segment")
private String customerSegment;
#JsonFormat(pattern="dd-MMM-yyyy")
#Column(name = "engagement_start_on")
private Date engagementStartOn;
#JsonManagedReference
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private List<CustomerDepartment> customerDepartments;
}
CustomerDepartment:-
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#DynamicUpdate
#Entity
#Table(name = "customer_department")
public class CustomerDepartment extends Auditable<Integer>{
#Id
#Column(name = "dept_id", updatable = false, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer deptId;
#Column(name = "dept_name")
private String deptName;
#Column(name = "primary_contact")
private String primaryContact;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "customer_no", nullable = false)
private Customer customer;
}
Current RequestBody:-
{
"createdBy": 0,
"creationDate": "2019-08-02T23:05:33.993Z",
"customer": {
"addressLine1": "string",
"addressLine2": "string",
"addressLine3": "string",
"city": "string",
"country": "string",
"createdBy": 0,
"creationDate": "2019-08-02T23:05:33.993Z",
"customerDepartments": [
null
],
"customerName": "string",
"customerNo": 0,
"customerSegment": "string",
"engagementStartOn": "string",
"industry": "string",
"lastUpdateDate": "2019-08-02T23:05:33.993Z",
"lastUpdatedBy": 0,
"paymentTerm": "string",
"postalCode": "string",
"state": "string"
},
"deptId": 0,
"deptName": "string",
"lastUpdateDate": "2019-08-02T23:05:33.994Z",
"lastUpdatedBy": 0,
"primaryContact": "string"
}
expected requestbody:-
{
"createdBy": 0,
"creationDate": "2019-08-02T23:05:33.993Z",
"customer": 1, //id instead of json
"deptId": 0,
"deptName": "string",
"lastUpdateDate": "2019-08-02T23:05:33.994Z",
"lastUpdatedBy": 0,
"primaryContact": "string"
}
Have you considered a unidirectional #OneToMany: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations?
For example on CustomerDeparment change
#JsonBackReference
#ManyToOne
#JoinColumn(name = "customer_no", nullable = false)
private Customer customer;
}
to
#JsonBackReference
#ManyToOne
#Column(name = "customer_no")
private int customer;
...and on Customer change
#JsonManagedReference
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private List<CustomerDepartment> customerDepartments;
}
to
#JsonManagedReference
#OneToMany(cascade = CascadeType.ALL)
private List<CustomerDepartment> customerDepartments;
}
As a bit of an aside, I honestly find Hibernate relationships to sometimes be more a hindrance than a help. As an alternative, you may wish to consider dropping the explicit relationship properties, using "regular" columns (#Column(name="customer_no") private int customer') and just writing queries in your repo classes (ex. findByCustomerNo(int customNumber)) to meet your requirements.
I have three tables
employee: storing employee information
role_description: storing types of role i have like admin, zone manger, country manager
employee_role_details: having many to many relationship from employee and role description with some extra fields.
Now I am facing an issue in fetching result that contains (employee_id, email) from employee table, (role_ownership, role_id) from employee_role_details and (role_name and role_description)from role_description corresponding to role_id in role_description.
Employee.java
#Entity
#Table(name = "employee", uniqueConstraints= #UniqueConstraint(columnNames={"employee_email"}))
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "employee_id")
private long employeeId;
#Column(name = "employee_name")
private String employeeName;
#Column(name = "employee_email", unique = true, nullable = false)
private String employeeEmail;
#Column(name = "contact_no")
private String contactNo;
#Column(name = "password")
private String password;
#Column(name = "is_active")
private Boolean isActive = true;
#Transient
private long EmployeeRoleId;
#Transient
private String roleName;
#Transient
private int totalpage;
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
//#JsonIgnore
#JsonManagedReference(value = "employeeRoleRecord-employee")
#LazyCollection(LazyCollectionOption.FALSE)
private List<EmployeeRoleRecord> roleRecords = new ArrayList<>();
#OneToMany(mappedBy = "assignedTo", cascade = CascadeType.ALL)
#JsonManagedReference(value = "complaint-treatment-employee")
#LazyCollection(LazyCollectionOption.FALSE)
private List<ComplaintsCategory> complaintCategoryAssignedTo = new ArrayList<>();
EmployeeDescription.java
#Entity
#Table(name = "role_description")
public class RoleDescription {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private long roleId;
#Column(name = "role_name")
private String roleName;
#Column(name = "role_description")
private String roleDescription;
#Column(name = "status")
private boolean status;
#OneToMany(mappedBy = "description", cascade = CascadeType.ALL)
#JsonManagedReference(value = "employeeRoleRecord-roleDescription")
#LazyCollection(LazyCollectionOption.FALSE)
private List<EmployeeRoleRecord> roleRecords = new ArrayList<EmployeeRoleRecord>();
EmployeeRoleRecord
#Entity
#Table(name = "employee_role_record")
public class EmployeeRoleRecord {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "employee_role_id")
private long employeeRoleId;
#Column(name = "role_ownership")
private String roleOwnership;
#Column(name = "status")
private boolean status = true;
#ManyToOne(cascade=CascadeType.ALL)
#JsonBackReference(value = "employeeRoleRecord-employee")
#JoinColumn(name = "employee_id")
private Employee employee;
#ManyToOne(cascade=CascadeType.ALL)
#JsonBackReference(value = "employeeRoleRecord-roleDescription")
#JoinColumn(name = "role_id")
private RoleDescription description;
#Transient
private long roleId;
Code inside a dao
public Employee getEmployeeByEmail(String email) {
return (Employee) sessionFactory.getCurrentSession()
.createCriteria(Employee.class)
.add(Restrictions.eq("employeeEmail", email)).uniqueResult();
}
services:
public Employee getSurveyData(String employeeEmail){
Employee loggedInEmployee =
loginDao.getEmployeeByEmail(employeeEmail);
Employee loggedInEmployeeRecord = new Employee();
loggedInEmployeeRecord.setEmployeeId(loggedInEmployee.getEmployeeId());
loggedInEmployeeRecord.setEmployeeName(loggedInEmployee.getEmployeeName());
List<EmployeeRoleRecord> employeeRoleRecords = loggedInEmployee.getRoleRecords();
List<EmployeeRoleRecord> employeeRoleRecord = new ArrayList<>();
for(EmployeeRoleRecord record : employeeRoleRecords){
EmployeeRoleRecord employeeRole = new EmployeeRoleRecord();
employeeRole.setRoleId(record.getDescription().getRoleId());
employeeRole.setRoleName(record.getDescription().getRoleName());
employeeRole.setRoleOwnership(record.getRoleOwnership());
employeeRole.setStatus(record.isStatus());
employeeRoleRecord.add(employeeRole);
}
loggedInEmployeeRecord.setRoleRecords(employeeRoleRecord);
return loggedInEmployee;
}
Output:
{
"employeeId": 1,
"employeeName": "Dhyanandra Singh",
"employeeEmail": "admin",
"contactNo": "9893651872",
"password": "123456",
"isActive": true,
"roleRecords": [
{
"employeeRoleId": 1,
"roleOwnership": "overall project",
"status": true,
"roleId": 0,
"roleName": null
}
],
}
problem:
json output i'm getting is not containing role id and role name in role records list.
The problem is:
Your roleId attribute on EmployeeRoleRecord classe is mapped as #Transient, which means that it is not persisted on database, so Hibernate is not able to fetch the result of this field.
Looking at your classes modeling I couldn't figure out exactly what you are trying to map with the roleId, I suggest two possible approaches:
Do not return directly your query on getEmployeeByEmail method. First get the results, then iterate it and set manually the desired roleId you want on each record;
Check your model scheme and make the correct mapping for roleId, it probably should reference another entity, so make sure to map the relationship correctly to get your results on a single query.
Good luck.
added transient roleId and roleName in EmployeeRoleRecord then having some modification in services. like iterating list setting roleId and roleName in it.
public Employee getSurveyData(String employeeEmail){
Employee loggedInEmployee =
loginDao.getEmployeeByEmail(employeeEmail);
Employee loggedInEmployeeRecord = new Employee();
loggedInEmployeeRecord.setEmployeeId(loggedInEmployee.getEmployeeId());
loggedInEmployeeRecord.setEmployeeName(loggedInEmployee.getEmployeeName());
loggedInEmployeeRecord.setEmployeeEmail(loggedInEmployee.getEmployeeEmail());
loggedInEmployeeRecord.setContactNo(loggedInEmployee.getContactNo());
List<EmployeeRoleRecord> employeeRoleRecords = loggedInEmployee.getRoleRecords();
List<EmployeeRoleRecord> employeeRoleRecord = new ArrayList<>();
for(EmployeeRoleRecord record : employeeRoleRecords){
EmployeeRoleRecord employeeRole = new EmployeeRoleRecord();
employeeRole.setEmployeeRoleId(employeeRole.getEmployeeRoleId());
employeeRole.setRoleId(record.getDescription().getRoleId());
employeeRole.setRoleName(record.getDescription().getRoleName());
employeeRole.setRoleOwnership(record.getRoleOwnership());
employeeRole.setStatus(record.isStatus());
employeeRoleRecord.add(employeeRole);
}
loggedInEmployeeRecord.setRoleRecords(employeeRoleRecord);
return loggedInEmployeeRecord;
}
I just cannot get the relationship working between my two classes mapped to SQL tables with Hibernate.
The Role class:
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="memberinfo")
private Set<Memberinfo> members;
...
}
And the Memberinfo class:
#Entity
#Table(name = "memberinfo")
public class Memberinfo {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
private int id;
#Column(name = "userid", nullable = false)
private String userid;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "salt", nullable = false)
private String salt;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "address")
private String address;
#Column(name = "phonenum")
private String phonenum;
#ManyToOne(targetEntity=Role.class)
#JoinColumn(name="role_id")
private Role role;
...
}
When i try to fetch data from the DB, it connects, but throws an exception:
"HTTP Status 500 - #OneToOne or #ManyToOne on model.Memberinfo.role references an unknown entity: model.Role".
If i delete the variable "Role", then it works, and i can fetch the membership data, but i need the connection between the two tables, but in this case, the previously mentioned exception appears every time.
No other solutions on stackoverflow worked for me so far.
Any idea what am i doing wrong?
The "unknown entity error" can be thrown if the class is not actually an Entity (not annotated whith javax.persistence #Entity) or if the persitence provider doesn't "know" the class (package not scanned).
Is the Role class imported in Memberinfo the correct one ? Maybe you are importing another Role class from another library.