Fetch result in case of many to many relationship - java

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;
}

Related

I need to get all distinct columns from the same table by the same code utilizing Hibernate

I have a table with n x n relationship. That means i have a code that is repeated with only a "brand" column being different between them. The code is not the ID.
I need to have one distinct class that contains all repeatable values and with a list that has all the unique brand column values.I cannot show most of the code samples because of my company security policies. But the entity below is a mock of what i'm seeking.
`
#Entity
#Table(name = "Table")
public class Teste {
#Column(name = "CODE", insertable = false, updatable = false)
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "BRAND")
private String brand;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "BRAND", joinColumns = { #JoinColumn(name = "CODE"), #JoinColumn(name = "BRAND")})
private Set<Model> brands = new HashSet<>();
#Column(name = "UPDATE_DATE")
private Date update_date;
#Column(name = "EDITOR")
private String editor;
#Id
#Column(name = "ID")
private int id;
}
`

Spring Boot Data JPA detached entity passed to persist on #OneToMany and #OneToOne

Problem
I am trying to store an object in my Postgres database. This consists of the Order.class, (List) OrderDevice.class, and a Department.class.
The important thing is that the OrderDevices are always stored new in the DB, but a Department may already exist.
When I try to save the object to my database using save I get the following error message: (shown below)
I get the error message "detached entity passed to persist: com.niclas.model.OrderDevice" if the department does not exist yet, if the department exists the error message looks like this: "detached entity passed to persist: com.niclas.model.Department".
Solution attempts
This solution cannot be used because I do not use bidirectional mapping.
(I don't want to use a bidirectional mapping because I want to access the departments without an order.)
I also tried to change the Cascade types to MERGE like in this solution
I also tried using #Transactional on the method
I also tried to save the children in the database first and then the parent like this:
departmentRepository.save(order.getDepartment()); orderDeviceRepository.saveAll(order.getDevices()); orderRepository.save(order);
I hope I have described my good enough and I am happy about suggestions for solutions
Error.log
The log can be viewed here. (The formatting did not work here)
Order.class
#Entity
#Table(name = "orders")
public class Order extends AuditModel {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;
#Column(name = "order_id")
private String orderId;
#Column(name = "department_id")
private long departmentId;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "department", referencedColumnName = "id")
private Department department;
#JsonProperty("deviceList")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "order_id", referencedColumnName = "order_id")
private List<OrderDevice> devices;
#JsonProperty("forename")
#Column(name = "sender_forename")
private String senderForename;
#JsonProperty("surname")
#Column(name = "sender_surname")
private String senderSurname;
#Column(name = "notes", columnDefinition = "TEXT")
private String notes;
#Column(name = "month")
private int month;
#Column(name = "year")
private int year;
public Order() {
}
... Getter/Setters
}
OrderDevice.class
#Entity
#Table(name = "order_devices")
public class OrderDevice extends AuditModel{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;
#Column( name = "order_id", insertable = false, updatable = false )
private String orderId;
#Column(name = "device_id")
private long deviceId;
#Column(name = "device_name")
private String deviceName;
#Column(name = "priceName")
private String priceName;
#Column(name = "price")
private double price;
#Column(name = "count")
private int count;
public OrderDevice() {
}
... Getters/Setters
}
Department.class
#Entity
#Table(name = "departments")
public class Department {
//TODO add Form Validation
//TODO better Naming for From Attributes on Frontend and Backend
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;
#Column(name = "department_name")
private String department;
#Column(name = "contact_person_forename")
private String forename;
#Column(name = "contact_person_surname")
private String surname;
#Column(name = "contact_person_mail")
private String mail;
#Column(name = "street")
private String street;
#Column(name = "house_number")
private String houseNumber;
#Column(name = "location")
private String location;
#Column(name = "postal_code")
private int postalCode;
#Column(name = "country")
private String country;
#Column(name = "auto_send_invoice")
private boolean autoSend;
#Column(name = "registered")
private boolean registered;
public Department() {
}
... Getter/Setters
}
OrderController.class
#Slf4j
#RestController
public class OrderController {
private final DepartmentRepository departmentRepository;
private final OrderRepository orderRepository;
private final OrderDeviceRepository orderDeviceRepository;
public OrderController(OrderRepository orderRepository, DepartmentRepository departmentRepository,
OrderDeviceRepository orderDeviceRepository) {
this.orderRepository = orderRepository;
this.departmentRepository = departmentRepository;
this.orderDeviceRepository = orderDeviceRepository;
}
#PostMapping("/orders/add")
public ResponseEntity<Order> addDepartment(#RequestBody Order order) throws JsonProcessingException {
order.setOrderId(order.generateOrderId());
DateTime dateTime = new DateTime();
order.setMonth(dateTime.getMonthOfYear());
order.setYear(dateTime.getYear());
order.getDevices().forEach(orderDevice -> {
orderDevice.setOrderId(order.getOrderId());
});
//departmentRepository.save(order.getDepartment());
//orderDeviceRepository.saveAll(order.getDevices());
orderRepository.save(order);
return new ResponseEntity<>(order, HttpStatus.CREATED);
}
Update
If the objects are created in this way, no error will occur and the order will be successfully saved in the database.
However, I don't understand why it works this way and not via ObjectMapper. Does anyone know why?
#PostMapping("/orders/add")
public ResponseEntity<Order> addDepartment(#RequestBody JsonNode jsonNode) throws JsonProcessingException {
Order order = new Order();
JsonNode departmentJson = jsonNode.get("department");
Department department;
if ( departmentJson.get("id").canConvertToInt() ) {
department = departmentRepository.findDepartmentById(departmentJson.get("id").asInt());
} else {
department = new Department();
department.setDepartment(departmentJson.get("department").asText());
department.setForename(departmentJson.get("forename").asText());
department.setSurname(departmentJson.get("surname").asText());
department.setMail(departmentJson.get("mail").asText());
department.setStreet(departmentJson.get("street").asText());
department.setHouseNumber(departmentJson.get("houseNumber").asText());
department.setLocation(departmentJson.get("location").asText());
department.setPostalCode(departmentJson.get("postalCode").asInt());
department.setCountry(departmentJson.get("country").asText());
department.setAutoSend(departmentJson.get("autoSend").asBoolean());
department.setRegistered(departmentJson.get("registered").asBoolean());
}
order.setDepartment(department);
order.setOrderId(order.generateOrderId());
order.setDepartmentId(department.getId());
List<OrderDevice> orderDevices = new ArrayList<>();
JsonNode devices = jsonNode.get("deviceList");
for (JsonNode node : devices) {
//TODO replace this mess with objectMapper
if (node.has("count") && node.get("count").asInt() != 0){
OrderDevice device = new OrderDevice();
device.setOrderId(order.getOrderId());
device.setDeviceId(node.get("id").asLong());
device.setDeviceName(node.get("deviceName").asText());
device.setPriceName(node.get("priceName").asText());
device.setPrice(node.get("price").asDouble());
device.setCount(node.get("count").asInt());
orderDevices.add(device);
}
}
order.setDevices(orderDevices);
order.setSenderForename(jsonNode.get("forename").asText());
order.setSenderSurname(jsonNode.get("surname").asText());
order.setNotes(jsonNode.get("notes").asText());
DateTime dateTime = new DateTime();
order.setMonth(dateTime.getMonthOfYear());
order.setYear(dateTime.getYear());
orderRepository.save(order);
return new ResponseEntity<>(order, HttpStatus.CREATED);
}
You can try to use instead of orderRepository.save(order) use orderRespostiory.saveOrUpdate(order).

Spring boot JPA related entity clarification

I have an entity like Process, which will be created by , updated by one user. When I try to apply the filter. I have created the foreign key relationship in the database. Now, when I use the JPA Specification to apply dynamic filter, I am getting exception as
No property CREATED found for type Process!
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id = null;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name = null;
#Column(name = "CREATED_BY", updatable = false)
#JsonProperty("createdBy")
private Long createdBy = null;
#Column(name = "updatedBy", nullable = true)
#JsonProperty("updatedBy")
private Long updatedBy = null;
}
Hence, I Added the entity relationship mapping in the process entity as given below,
Now, I am getting below error. I am new to JPA and hibernate, the relation mapping is very confusing, kindly help.
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id = null;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name = null;
#Column(name = "CREATED_BY", updatable = false)
#JsonProperty("createdBy")
private Long createdBy = null;
#Column(name = "updatedBy", nullable = true)
#JsonProperty("updatedBy")
private Long updatedBy = null;
//newly added below properties so that there will be no error when fetching data
#OneToOne(targetEntity = UserDetails.class, fetch = FetchType.LAZY, mappedBy = "id")
private UserDetails CREATED;
#OneToOne(targetEntity = UserDetails.class, fetch = FetchType.LAZY, mappedBy = "id")
private UserDetails UPDATED;
}
Now, I am getting the below error
Referenced property not a (One|Many)ToOne: com.app.users.details.domain.UserDetails.id in mappedBy of com.app.scenarios.domain.Process.CREATED
Kindly let me know what i am doing wrong. I have a process which can be created by a user and can be updated by a user. In DB, I am having a foreign key relationship for process and userdetails entity.
EDIT
Code to get the filtered data from DB using JPA Specification
Page<process> result = this.processDao.findAll(getprocessGridData(processSearchCondition.getprocessName()), pageRequest);
private static Specification<process> getprocessGridData(String processName) {
return (Specification<process>) (root, query, criteriaBuilder) -> (
criteriaBuilder.like(root.get("name"), processName)
);
}
I guess what you actually want is this:
#Table(name = "process")
#Entity
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PROCESS_ID")
#JsonProperty("id")
private Long id;
#NotNull
#Column(name = "NAME")
#JsonProperty("name")
private String name;
#OneToOne(fetch = FetchType.LAZY)
#jOINColumn(name = "CREATED_BY", updatable = false)
private UserDetails createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UPDATED_BY", nullable = true)
private UserDetails updatedBy;
}

Hibernate unable to map many students to a class

I hae 2 simple entities: Student and Class. I want to POST a student, where I specify the class it belongs to, but I've got stuck in hibernate mapping.
ClassModel.class
#Entity
#Table(name = "class" )
public class ClassModel implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty
#Size(max = 20)
#Column(name = "name")
private String name;
#Column(name = "tables")
private int tables;
#Column(name = "chairs")
private int chairs;
#Column(name = "teacher")
private String teacher;
(getters + setters)
StudentModel
#Entity
#Table(name = "student")
public class StudentModel implements Serializable {
#Id
#Column(name = "student_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int student_id;
#NotEmpty
#Column(name = "name")
#Size(max = 50)
private String name;
#Column(name = "age")
private int age;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private ClassModel classModel;
(getters + setters)
}
StudentController.java
...
#Autowired
private StudentService studentService;
#Autowired
private ClassService classService;
#PostMapping(value = "/save")
public StudentModel save(#RequestBody StudentModel studentModel){
ClassModel classModel = classService.findById(studentModel.getClassId()).get();
studentModel.setClassModel(classModel);
return studentService.save(studentModel);
}
...
But when I make a request from Postman with the following body:
{
"name": "some name",
"age": 12,
"class_id": 1
}
I get the following error from hibernate:
Column 'class_id' cannot be null
Where is the mistake in my hibernate mapping?
It's how I have made working join in hibernate. Have a look:
TrainingEntity.java
#Id
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "animal_id", nullable = false, insertable = false, updatable = false)
private AnimalEntity animalEntity;
#Column(name = "animal_id")
private Integer animalId;
AnimalEntity.java
#Id
private Integer id;
#OneToMany(mappedBy = "animalEntity", fetch = FetchType.LAZY)
private List<TrainingEntity> trainingEntityList = new ArrayList<>();
So here is the join between AnimalEntity and TrainingEntity.
AnimalEntity have a list of TrainingEntities.
The mistake is in this line:
"class_id": 1
You're using column name instead of field name. You would have to replace class_id with classModel, where classModel would be an object. Other solution would be to find ClassModel by id from json and set it as parent to StudentModel.

How do I prevent duplicate items in the cart?

For the current structure of database:
database structure
Users
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "username", unique = true, nullable = false, length = 45)
private String username;
#Column(name = "password", nullable = false, length = 60)
private String password;
#Column(name = "enabled", nullable = false)
private boolean enabled;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade=CascadeType.ALL)
private Set<UserRole> userRole = new HashSet<UserRole>(0);
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(
name = "users_product",
joinColumns ={#JoinColumn (name = "users_username", referencedColumnName = "username")},
inverseJoinColumns = {#JoinColumn(name = "Products_idProducts", referencedColumnName = "idProducts")}
)
List<Products> productsList = new ArrayList<Products>();
Products
#Entity
#Table(name = "products")
public class Products implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idProducts")
private long id;
#Column(name = "description")
private String description;
#Column(name = "price")
private String price;
#Column(name = "image")
private byte [] image;
#ManyToMany(mappedBy = "productsList")
List<User> usersList = new ArrayList<User>();
//setters - getters
I want to implement a shopping basket.
What I have now: A page with products and checkboxes on the view page. I find these products and send them to my controller, and afterwards set them to the current user.
productsList = myService.findManyProducts(toAdd);
user.setProductsList(productsList);
myService.updateUser(user);
#Transactional
public void updateUser(User user){
userDao.update(user);
}
update user function:
#Override
public void update(User user) {
entityManager.merge(user);
}
These actions are entered in the database as different values, depending on the latest additions.
What I want:
User adds some products to cart, browse other items, and add new products to the cart. How do I ensure that duplicate items are not found in the cart? Does JPA have some standard methods? Or do I need to check the product list by myself before adding them to the database?
I solved this by changing the List collection to a Set in the User entity.

Categories