Get Join Table Data using Hibernate - spring

I have two tables and trying to get data with inner join using hibernate with spring.
And i will get json using ModelMapper and get duplicate record also.
So, please suggest me how to get unique record with inner join query using hibernate.
I have Two Tables:
Table Name: User
---------------------
id | email
---------------------
1 | m#gmail.com
2 | e#gmail.com
---------------------
Table Name: Userrole
----------------------------------------
roleid | userid | rolename
----------------------------------------
1 | 1 | Admin
2 | 1 | HR
3 | 2 | Employee
4 | 2 | Executive
----------------------------------------
#Entity
#Table(name="user")
public class User{
#Id
#GeneratedValue
private int id;
#Column
private String email;
#OneToMany
private List<Userrole> userroles;
public void setId(int id){
this.id = id;
}
public void setEmail(String email){
this.email= email;
}
public int getId(){
return id;
}
public String getEmail(){
return email;
}
public List<Userrole> getUserrole(){
return userroles;
}
}
#Entity
#Table(name="userrole")
public classs Userrole{
#Id
#GeneratorValue
private int roleid;
#Column
private String rolename;
#ManyToOne
private User user;
// setter and getter
}
public List<User> findAall(){
// Type casting will throw an error
// This will throw error
return (List<User>)session.getCurrentSession().createQuery("from User u join u.userroles");
// this will return List<Object[]>
return session.getCurrentSession().createQuery("from User u join u.userroles");
// So i want to convert to this DTO using ModelMapper object
}
public class UserDTO{
private int id;
private String email;
private List<Userrole> roleusers;
// setter and getter
}
public class UserroleDTO{
private int roleid;
private String rolename;
//settter and getter
}
public interface UserDao{
public List<User> findAll();
}
#Repository
public class UserDaoImpl implements UserDao{
#Override
public List<User> findAll(){
// This will throw an error: ClassCastException
return (List<User>)session.getCurrentSession().createQuery("from User u join u.userroles");
// This will work perfectly and return List<Object[]>
return session.getCurrentSession().createQuery("from User u join u.userroles");
}
}
#Controller
public class HomeController{
#Autowired
private UserDao doa;
ModelMapper modelMapper = new ModelMapper();
#RequestMapping(value="/list")
public List<User> findAll(){
List<User> list = dao.findAll();
List<UserDTO> dto = list.stream().map(user -> convertToDto(user)).collect(Collectors.toList());
return dto;
// This will return
[
{
"id":1,
"email":"m#gmail.com",
"userroles":[
{
"roleid":1,
"rolename":"Admin"
},
{
"roleid":2,
"rolename":"HR"
}
]
},
{
"id":1,
"email":"m#gmail.com",
"userroles":[
{
"roleid":1,
"rolename":"Admin"
},
{
"roleid":2,
"rolename":"HR"
}
]
},
{
"id":2,
"email":"e#gmail.com",
"userroles":[
{
"roleid":3,
"rolename":"Employee"
},
{
"roleid":4,
"rolename":"Executive"
}
]
},
{
"id":2,
"email":"e#gmail.com",
"userroles":[
{
"roleid":3,
"rolename":"Employee"
},
{
"roleid":4,
"rolename":"Executive"
}
]
}
]
// It should return
[
{
"id":1,
"email":"m#gmail.com",
"userroles":[
{
"roleid":1,
"rolename":"Admin"
},
{
"roleid":2,
"rolename":"HR"
}
]
},
{
"id":2,
"email":"e#gmail.com",
"userroles":[
{
"roleid":3,
"rolename":"Employee"
},
{
"roleid":4,
"rolename":"Executive"
}
]
}
]
}
public UserDTO convertToDto(User user){
UserDTO dto = modelMapper.map(user,UserDTO.class);
return dto;
}
}

Related

Many to One Relationship returns NULL List of Child Object

I have 2 classes. USER class & ORDER class.
Order class has User object with #ManyToOne relationship.
When the RestController retrieves the Order object post insertion of Order object using #PostMapping,it returns null value for nested User object
Rest Controller
#RestController
public class OrderController {
#PersistenceContext
EntityManager entityManager;
#Transactional
#PostMapping(value = "api/v1/create/order")
public Order createOrder(#RequestBody Order order){
entityManager.persist(order);
return order;
}
}
Order class
#Entity
#Table(name = "booking_order")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer orderID;
#Column
String transactionAmount;
#Column
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
Date bookingTimestamp;
#ManyToOne
User user;
public Order(){}
public Integer getOrderID() {
return orderID;
}
public void setOrderID(Integer orderID) {
this.orderID = orderID;
}
public String getTransactionAmount() {
return transactionAmount;
}
public void setTransactionAmount(String transactionAmount) {
this.transactionAmount = transactionAmount;
}
public Date getBookingTimestamp() {
return bookingTimestamp;
}
public void setBookingTimestamp(Date bookingTimestamp) {
this.bookingTimestamp = bookingTimestamp;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User Class
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
#Column(unique = true)
String username;
#Column
String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Input JSON
{
"transactionAmount" : "100.50",
"user":{
"id":1
}
}
Order Response
{
"orderID": 1,
"transactionAmount": "100.50",
"bookingTimestamp": "2019-05-15T20:44:43.234+0000",
"user": {
"id": 1,
"username": null,
"password": null
}
}

how to Fix spring boot one to many bidirectional infinity loop?

i am try to create a one to many bidirectional mapping using spring boot and spring data jpa please look the below entity
Employer Entity
#Entity
public class Employer
{
private Long id;
private String employerName;
private List<Employee> employees;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getEmployerName()
{
return employerName;
}
public void setEmployerName(String employerName)
{
this.employerName = employerName;
}
#OneToMany(cascade=CascadeType.ALL, mappedBy="employer")
public List<Employee> getEmployees()
{
return employees;
}
public void setEmployees(List<Employee> employees)
{
this.employees = employees;
}
}
Employee Entity
#Entity
public class Employee
{
private Long id;
private String employeeName;
private Employer employer;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getEmployeeName()
{
return employeeName;
}
public void setEmployeeName(String employeeName)
{
this.employeeName = employeeName;
}
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
public Employer getEmployer()
{
return employer;
}
public void setEmployer(Employer employer)
{
this.employer = employer;
}
}
Employer Repo
public interface EmployerServices extends JpaRepository<Employer, Long> {
}
Employee Repo
public interface EmployeeServices extends JpaRepository<Employee, Long> {
}
REST Controller is
#RestController
public class Controller {
#Autowired EmployeeServices employeeServices;
#Autowired EmployerServices employerServices;
#GetMapping("/getempr")
public Object getempr(){
return employerServices.findOne(1L);
}
}
now the problem begin start see my out put
its look like a infighting loop and my server throwing error getOutputStream() has already been called for this response.
I used #JsonBackReference & #JsonManagedReference
annotation but the problem is its working like one to many
{
"id":1,
"employerName":"employer",
"employees":[
{"id":1,"employeeName":"emp1"},
{"id":2,"employeeName":"emp2"}
]
}
if I am trying to get in the concern of many to one like all employee with employer. the output is
[
{
"id":1,
"employeeName":"emp1"
},
{
"id":2,
"employeeName":"emp2"}
]
its not showing me the employer details.
please suggets me guys what i am doing wrong. thanks in advance!!
Instead of using #JsonBackReferenceand #JsonManagedReference try to use annotation #JsonIgnoreProperties:
#JsonIgnoreProperties("employer")
private List<Employee> employees;
#JsonIgnoreProperties("employees")
private Employer employer;
It prevents Jackson from rendering a specified properties of associated objects.
with the JSON its a problem with bi-directional mapping. Use the below properties.
#JsonIgnoreProperties("employer")
#JsonIgnoreProperties("employees")
please keep fetching type as eager.
hope this will work.
You can solve your issue with two modification with annotations.
Employer.class
#Entity
public class Employer {
private Long id;
private String employerName;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "employer",
orphanRemoval = true)
private List<Employee> employees;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmployerName() {
return employerName;
}
public void setEmployerName(String employerName) {
this.employerName = employerName;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
Employee.class
#Entity
public class Employee {
private Long id;
private String employeeName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employer_id")
private Employer employer;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employer getEmployer() {
return employer;
}
public void setEmployer(Employer employer) {
this.employer = employer;
}
}
For more information please visit this link.
Change your getEmployer Method like this:
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public Employer getEmployer()
{
return employer;
}
use
#JsonProperty(access = Access.WRITE_ONLY)
private List<Employee> employees;
So that it will ignore employees while printing to JSON in the response (and thus prevents the looping), but will still consider the JSON data (employee list) you pass in the request body so that it is available for persistence.

#OneToMany mapped by doesn't make an entry to the table

Here I have two entity class. I used OneToMany and ManyToOne mapping.
#Entity
#Table(name="test_user")
public class TestUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer user_id;
private String user_name;
#OneToMany(mappedBy = "testuser", fetch=FetchType.EAGER, cascade = CascadeType.ALL)
private Set<UserAnswer> answer = new HashSet<UserAnswer>();
public Set<UserAnswer> getAnswer() {
return answer;
}
public void setAnswer(Set<UserAnswer> answer) {
this.answer = answer;
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
}
This is my second entity class
#Entity
#Table(name="user_answer")
public class UserAnswer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer answer_id;
private String answer;
#ManyToOne
#JoinColumn(name="user_id")
private TestUser testuser;
public TestUser getTestuser() {
return testuser;
}
public void setTestuser(TestUser testuser) {
this.testuser = testuser;
}
public Integer getAnswer_id() {
return answer_id;
}
public void setAnswer_id(Integer answer_id) {
this.answer_id = answer_id;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
When I insert user and answer, user_id is not getting stored in user_answer table.
Here is my JSON input format.
{
"user_name":"myname",
"answer":[
{
"answer":"myanswer"
}
]
}
When I fetch the data I am getting JSON response like this,
[
{
"user_id": 52,
"user_name": "myname",
"answer": []
}
]
Here is my service code snippet,
#Autowired
private TestUserRepository repo;
#Override
public TestUser addUser(TestUser user) {
return repo.save(user);
}
Here is my controller code snippet
#Autowired
private TestUserApiService service;
#RequestMapping(value = "/saveuser", produces = { "application/json" }, consumes = { "application/json" }, method = RequestMethod.POST)
public ResponseEntity<TestUser> addUser(#RequestBody TestUser user)
throws NotFoundException {
return new ResponseEntity<TestUser>(service.addUser(user),
HttpStatus.OK);
}
The relation you have here is bidirectional, which means each side of the relation should have a reference to the other side.
Your input format has TestUser which has a UserAnswer set since you are cascading your UserAnswer inside your TestUser you would expect to persist the relation, but your UserAnswer should have a reference to TestUser as well to complete the relations.
you can do two things, first you can make your relation unidirectional, or you can extract the coming UserAnswer and inject the TestUser to them then persist the TestUser

Creating a node in neo4j with one unique property other than ID

My Project is based on Spring boot + Neo4j .
I am trying to create a new Privilege node , but don't want to duplicate Privilege.
Now I have a UserRole node which is holds List<Privilege>. Now
I want that when I create a Privilege , it check first is another Privilege exists with same privilegeName property.
Below are my domain classes.
UserRole Class
#NodeEntity
public class UserRole {
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
/**
For Jackson Parsing
**/
public UserRole() {
}
#GraphId
private Long id;
public UserRole(User user, Role role, Unit unit) {
this.user = user;
this.role = role;
this.unit = unit;
}
public long getId() {
return id;
}
#Relationship(type = HAS_USERROLE,direction = "OUTGOING")
User user;
public User getUser() {
return user;
}
#Relationship (type = HAS_ROLE_OF,direction = "OUTGOING")
Role role;
public Role getRole() {
return role;
}
#Relationship(type = "WORKS_IN",direction = "OUTGOING")
Unit unit;
public Unit getUnit() {
return unit;
}
public void setUnit(Unit unit) {
this.unit = unit;
}
#Relationship(type = "HAS_PRIVILEDGE", direction = "OUTGOING")
List<Priviledge> priviledgeList;
public List<Priviledge> getPriviledgeList() {
return priviledgeList;
}
public void setPriviledgeList(List<Priviledge> priviledgeList) {
this.priviledgeList = priviledgeList;
}
}
Privilege Class
#GraphId
Long id;
private String priviledge;
private String priviledgeOn;
private Long priviledgeOnId;
public Priviledge() {
}
public Priviledge(String priviledge, String priviledgeOn) {
this.priviledge = priviledge;
this.priviledgeOn = priviledgeOn;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPriviledge() {
return priviledge;
}
public void setPriviledge(String priviledge) {
this.priviledge = priviledge;
}
public String getPriviledgeOn() {
return priviledgeOn;
}
public void setPriviledgeOn(String priviledgeOn) {
this.priviledgeOn = priviledgeOn;
}
public Long getPriviledgeOnId() {
return priviledgeOnId;
}
public void setPriviledgeOnId(Long priviledgeOnId) {
this.priviledgeOnId = priviledgeOnId;
}
}
I am Using GraphRepository to save Entities.
The only way to do this currently is to query for the Privilege existing first and then create it if not, or use it if it does. Also add a unique constraint to be safe.
In a future release, this use case will be supported.

Sprint Date Rest successful, but no data

Entity
#Data
#Accessors(chain = true, fluent = true)
#Entity
#Table(name = "T_NOTE")
#Access(AccessType.FIELD)
public class Note implements Serializable
{
#Id
#GeneratedValue
private Long id;
private Date date;
#Column(length = 2000)
private String content;
private String title;
private String weather;
}
Repository
#RepositoryRestResource(collectionResourceRel = "note", path = "note")
public interface NoteRepository extends AbstractRepository<Note, Long>
{
}
GET http://localhost:8080/note/2
{
"_links": {
"self": {
"href": "http://localhost:8080/note/2"
}
}
}
No entity field data, why?
EIDT
After I add standard setter/getter, everything is ok now.
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getWeather()
{
return weather;
}
public void setWeather(String weather)
{
this.weather = weather;
}
Is this cause by jackson mapper ? How can I use fluent API with this ?Why not just use reflection to generate JSON ?
EDIT
What I need is this configuration
#Configuration
#Import(RepositoryRestMvcConfiguration.class)
public class ShoweaRestMvcConfiguration extends RepositoryRestMvcConfiguration
{
#Override
protected void configureJacksonObjectMapper(ObjectMapper mapper)
{
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}
}
Caused by this
#Accessors is probably stepping over the #Data annotation, and with fluent = true it generates getters with the same name as the field, like id() and date() (#Accessor documentation). That's why Spring doesn't see any of the fields.
I think you can safely remove both #Accessors and #Access, since #Access's takes the default value from id (if you annotated the field, it will be FIELD, if you annotated the getter, it will be PROPERTY).

Resources