I am trying to join three entities (table) using spring-jpa into one table using Many-To-Many relationship.
Three classes are :
1] User
2] Resource
3] Privilege
And I want to combine these three entities into one User_Resource_Privilege table
User Entity
package com.****.acl.domain;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
#Entity
public class User {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="user_id", nullable=false, length=40)
private String userId;
#Column(name="user_name", nullable=false, length=45)
private String userName;
#Column(name="first_name", nullable=true, length=45)
private String firstName;
#Column(name="last_name", nullable=true, length=45)
private String lastName;
#Column(name="email", nullable=true, length=50)
private String email;
public User(){
}
public User(String userName, String firstName, String lastName, String email) {
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
getter and setters .......
}
Resource Entity
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
#Entity
public class Resource {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="resource_id", nullable=false, length=40)
private String resourceId;
#Column(name="resource_name", nullable=false, length=45)
private String name;
#Column(name="resource_type", nullable=false, length=45)
private String type;
public Resource(){
}
public Resource(String name, String type) {
this.name = name;
this.type = type;
}
getter and setter ......
}
Privilege Entity
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
#Entity
public class Privilege {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="privilege_id", nullable=false, length=40)
private String privilegeId;
#Column(name="resource_name", nullable=false, length=45)
private String name;
#Column(name="resource_description", nullable=true, length=45)
private String description;
public Privilege(){
}
getters and setters ....
}
Now I want to create one table by joining all the three entities described above.
The join in ER diagram:
Can someone please help me in joining these three tables using Many-To-Many relationship and let me know how to achieve this using spring-jpa and REST ?
Also it will be great if you please explain how to insert data in this "User_Resource_Privilege" table using REST/curl command ?
What you could do is make an embeddable ID and wrap it with the class. You can afterwards even expand this wrapper class to hold other fields.
java geeks example of embedded id
You would get something like
#Embeddable
public class EmbeddedIdClass implements Serializable {
private String userId;
private String resourceId;
private String privilegeId;
// constructors, getters and setters, equals, etc
}
#Entity
public class Wrapper {
#EmbeddedId
private EmbeddedIdClass id;
// constructors, etc
}
Instead of just using the strings in this example, you should use the complete objects and let hibernate (or something like it) do it's stuff. It should only take the id's into the database and do it's magic itself.
edit:
Just wanting to insert the id's as values, but keeping relationships would look something like this
#Entity
public class Wrapper {
#Id
private String id;
private User user;
private Resource resource;
private Privilege privilege;
// constructors
public Wrapper(final User user, final Resource resource, final Privilege privilege) {
this.user = user;
this.resource = resource;
this.privilege = privilege;
}
}
Related
I am using Java and Sprig boot with MySQL to create an employee tracker. there are to models: Employee and Company. The Company model just has an autogenerated Id and name. The employee has first_name, last_name, address, salary, company_id, and email_id. The Employee Model belongs to Company model, and it is a oneToMany relationship (because one company has many employees. I am trying to set it up so that the Employee model is linked to the Company model. When I try and run spring boot i get this error:
Use of #OneToMany or #ManyToMany targeting an unmapped class: employeeapps.com.example.EmployeeTracker.model.Employee.company[employeeapps.com.example.EmployeeTracker.model.Company]
Here is my Employee Model:
package employeeapps.com.example.EmployeeTracker.model;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "employees")
public class Employee {
//Company is one and has many employees
#OneToMany(mappedBy = "employees")
private Set<Company> company;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long companyId;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name="address")
private String address;
#Column(name="salary")
private Double salary;
#Column(name = "email_id")
private String emailId;
//default constructor
public Employee(){
}
//create a public constructor with the appropriate parameters to be able to create a new instance of an employee
public Employee(String firstName, String lastName, String emailId, String address, Double salary){
super();
this.firstName = firstName;
this.lastName = lastName;
this.emailId = emailId;
this.salary = salary;
this.address = address;
}
//define methods
//long data type because could be a very long numerical data
public long getId() {
return companyId;
}
public void setId(long companyId){
this.companyId = companyId;
}
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 getEmailId(){
return emailId;
}
public void setEmailId(String emailId){
this.emailId = emailId;
}
public void setAddress(String address){
this.address = address;
}
public void setSalary(Double salary){
this.salary = salary;
}
Here is my Compay Model:
package employeeapps.com.example.EmployeeTracker.model;
import javax.persistence.*;
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name")
private String name;
public Company(){
}
//public constructor
public Company(String name){
this.name = name;
}
}
Here is my employee controller to preform REST API:
package employeeapps.com.example.EmployeeTracker.controller;
import employeeapps.com.example.EmployeeTracker.model.Employee;
import employeeapps.com.example.EmployeeTracker.repository.employeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/api/v1")
public class EmployeeController {
#Autowired
private employeeRepository employeeRepository;
//REST APIS
//get all employees method name is get all
#GetMapping("/employees")
public List<Employee> getAllEmployees(){
return employeeRepository.findAll();
}
}
In the company model give the model #Entity annotation above #Table annotation.
Add below line to your system.properties file
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
In employees class use :
#OneToMany(targetEntity = Employee.class,cascade = ALL,fetch =
FetchType.LAZY)
#JoinColumn(name = "employee_id",referencedColumnName = "company_id")
private Set<Company> company;
You should make the company an entity because you cannot make mapping without making the model class into the entity.Use #Entity to make company class entity above #Table(name = company).
As you are trying to map from employees(many) entity to company(one)entity
try #ManyToOne mapping in the employees entity by making company_
id a FOREIGN KEY in employee table
#ManyToOne
#JoinColumn(name="id",referencedColumnName="company_id")
private Set<Company> company;
In the above name represents id of company in company entity and referencedColumnName represents company_id in the employee entity.
I want to have the relationship OneToMany between two entity but I have this error when I try to save object into database:
on console
java.lang.IllegalArgumentException: Can not set java.lang.Long field com.pi.MinuteBrico.models.Category.idCtegory to java.util.LinkedHashMap
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58) ~[na:na]
at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36) ~[na:na]
at java.base/java.lang.reflect.Field.get(Field.java:419) ~[na:na]
on psotman
org.springframework.orm.jpa.JpaSystemException: Error accessing field [private java.lang.Long com.pi.MinuteBrico.models.Category.idCtegory] by reflection for persistent property [com.pi.MinuteBrico.models.Category#idCtegory] : {name=Mecanique}; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.Long com.pi.MinuteBrico.models.Category.idCtegory] by reflection for persistent property [com.pi.MinuteBrico.models.Category#idCtegory] : {name=Mecanique}\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:331)\r\n\tat org.springframework.orm.jpa.vendor.
my entities classes:
1: Bricoleur.java
package com.pi.MinuteBrico.models;
import java.util.Map;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
#Entity
#Table(name = "Bricoleur")
public class Bricoleur implements Serializable {
/**
*#author iliass Alilou
*/
private static final long serialVersionUID = 1L;
/*#SequenceGenerator(
name = "Bricoleur_sequence",
sequenceName = "Bricoleur_sequence",
allocationSize = 1
)
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "Bricoleur_sequence"
)*/
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String photo;
private String firstName;
private String lastName;
private String email;
private String phone;
private String birthDate;
private String adresse;
#OneToMany(/*fetch = FetchType.LAZY , targetEntity = Category.class,*/ cascade = CascadeType.ALL)
#JoinColumn(name = "BricoCategory_Bricoleur",referencedColumnName = "id")
private List<Category> category ;
public Bricoleur() {
}
public Bricoleur(String photo,
String firstName,
String lastName,
String email,
String phone,
String birthDate,
String adresse
) {
super();
this.photo = photo;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.phone = phone;
this.birthDate = birthDate;
this.adresse = adresse;
}
// setters and getters
... ..
}
2:Category
package com.pi.MinuteBrico.models;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="Category")
public class Category implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idCtegory;
private String name;
public Category() {
}
public Category(String name) {
super();
this.name = name;
}
// Stters and getters
}
JSON file to save
{
"photo":"test",
"firstName":"iliass",
"lastName":"alilou",
"email":"iliass20#gmail.com",
"phone":"0654248574",
"birthDate":"18/08/1999",
"adresse":"xxxxxxxxxxxx",
"category" : [
{
"name" : "Mecanique"
},
{
"name" : "Plombie"
}
]
}
In my Controller
#CrossOrigin()
#PostMapping("/bricoleur")
public String create(#RequestBody Map<String, Object> bricoleurMap) {
System.out.println(bricoleurMap);
Bricoleur bricoleur = new Bricoleur(bricoleurMap);
bricoleurService.saveBricoleur(bricoleur);
return "Bricoleur ajouté";
}
Service
public Bricoleur saveBricoleur(Bricoleur bricoleur) {
return bricoleurRepository.save(bricoleur);
}
The field category is of type List:
List<Category> category
but it seems you are trying to assign a LinkedHashMap, that's a Map.
Didn't you mean to use a LinkedList?
We need to see how you are assigning the field category to help you more.
I have a users table which contains the user details. i also have a authorities table which has the role of a user. The user and authorities table has one to many mapping. When i try to save the details using Jpa the foreign key column is blank no data is inserted in that field. i have a form in which i am specifying the role of the user along with other details.
package com.example.StarsProject.Model;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
#Entity
#Table
#Getter
#Setter
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String role;
#ManyToOne(cascade = CascadeType.PERSIST,fetch=FetchType.EAGER)
#JoinColumn(name = "users_id", referencedColumnName = "id")
private Users users;
public Authorities(String role){
this.role = role;
}
}
package com.example.StarsProject.Model;
import com.example.StarsProject.DTO.UserDTO;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table
#Getter
#Setter
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstname;
#Column(name = "last_name")
private String lastname;
#Column(unique = true)
private String email;
private String password;
#OneToMany(fetch = FetchType.EAGER,targetEntity = Authorities.class,mappedBy = "users", cascade = CascadeType.PERSIST)
private Set<Authorities> authorities;
public Users(UserDTO userDTO) {
this.email = userDTO.getEmail();
this.firstname = userDTO.getFirstname();
this.lastname = userDTO.getLastname();
this.password = userDTO.getPassword();
// Authorities authorities = new Authorities();
// authorities.setRole(userDTO.getRole());
// Set<Authorities> set = new HashSet<>();
// set.add(authorities);
this.authorities = new HashSet<Authorities>(Arrays.asList(new Authorities(userDTO.getRole())));
}
}
package com.example.StarsProject.Service;
import com.example.StarsProject.DTO.UserDTO;
import com.example.StarsProject.Model.Users;
import com.example.StarsProject.Repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class UserDetailsServiceImpl implements UserDetailsServiceInterface{
#Autowired
UserRepository userRepository;
#Override
public void storeUserDetails(UserDTO userDTO) {
Users users = new Users(userDTO);
userRepository.save(users);
}
}
When i try to save the user details it doesn't insert any value in the foreign key column. Can someone tell me what i am doing wrong.
You need to setusers field in Authorities manually. Hibernate won't fill it for you.
I've a Java REST API with JPA. Whenever I create an entity, I also want to create another entity with a forgein key. Or maybe someone can advise me otherwise, I would really appreciate it and learn from it =)
When i successfully create a company it will make a file entity in the database as well, so that works fine. but,
Whenever I execute a findAll method in the JPA repository it will give me a loop of the one company that i've created.
like this:
If you need any more information, please let me know!
Company.class
package nl.hulpvriend.dehulpvriend.company;
import javax.validation.constraints.NotNull;
import lombok.*;
import nl.hulpvriend.dehulpvriend.file.File;
import javax.persistence.*;
import javax.validation.constraints.Size;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
private String email;
#Column(unique = true)
#NotNull(message = "The company name cannot be empty")
#Size(max = 30, message = "Company name cannot be longer than 30 characters")
private String name;
#NotNull(message = "Company must contain a service type")
#Enumerated(EnumType.STRING)
private ServiceType serviceType;
private double stars;
private Integer pricePerHour;
private String description;
private String kvk;
#OneToOne(mappedBy="company", cascade = CascadeType.ALL)
private File file;
}
File.class
package nl.hulpvriend.dehulpvriend.file;
import lombok.*;
import nl.hulpvriend.dehulpvriend.company.Company;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
#AllArgsConstructor
#Getter
#Setter
#NoArgsConstructor
#Entity
#Data
public class File {
#Id
private Integer id;
private String fileId;
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;
#NotNull(message = "Must contain a data")
#Lob
private byte[] data;
private String downloadUrl;
private String fileName;
private String fileType;
public File(String fileName, String fileType, byte[] data) {
this.fileName = fileName;
this.fileType = fileType;
this.data = data;
}
}
Add JsonIgnore to one of the references to break the loop:
For example in the File class:
#JsonIgnore
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;
I have got this exception!!
here is my model class
#Entity
public class User extends Model {
#OneToMany(mappedBy="email", cascade=CascadeType.ALL)
public List<Photo> photo;
#Email
#Required
#Unique
public String email;
#Required
public String passwordHash;
#Required
public String education;
#Required
public String fname;
#Required
public String lname;
#Required
public Date dob;
#Required
public String gender;
#Required
public String country;
#Required
public Long phone;
#Required
public String status;
#Required
public String jobtitle;
#Required
public String company;
#Required
public String industry;
#Required
public Date addDate;
public String needConfirmation;
public User(String email, String password, String fname,
String lname, Date dob, String gender, String country,
Long phone, String status, String education, String jobtitle, String company, String industry) {
//all initialization here
}
}
can you please tell me where I am going wrong
playframework× 2289
this is my photo class, and please tell me how can I allow JPA to generate my database
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package models;
import controllers.Users;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;
/**
*
* #author nPandey
*/
#Entity
public class Photo extends Model{
public String photoname;
#ManyToOne
public User email;
public String owner;
public Photo(){
}
public Photo(User email, String photo){
this.photoname=photo;
this.email=email;
this.owner=email.email;
}
}
Check that your entity isn't missing any required fields when it's being persisted / updated. Also check what constraints are set on the User-table in the DB (unique keys, foreign keys, non nulls...).
Your mappedBy value makes little sense. It is used on the passive end of a bi-directional association. In those cases it points to the attribute on the other class on the other side of the relationship. You are pointing it to one of the attributes of the User class. Perhaps your Photo class has a email attribute, but is that of type User ( i am guessing not). So if this is a bi-directional association, set the mappedBy value to the attribute on Photo having the corresponding #ManyToOne "back" to the User. If it is a unidirectional association, remove the mappedBy and perhaps use #JoinColumn to use the foreign key mapping strategy of unidirectional one-to-many
I was facing same issue and it got resolved by changing relationship related notation from OneToMany to ManyToMany. In My case there was ManyToMany relation between Job and Person Table and I was trying to add same jobList to multiple person object in a loop.
The problem was with the annotation used in Person Entity class for Job Entity:
#ManyToMany // Changed from OneToMany to ManyToMany
private List<Job> jobList = new ArrayList<Job>();
Try editing the code as below -
In User Model
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
public List<Photo> photos;
In Photo Model
#ManyToOne
#NotFound(action = NotFoundAction.IGNORE)
#JoinColumn(name = "email", nullable = false, insertable = false, updatable = false)
public User user;
Check this for reference - http://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Example_of_a_OneToMany_relationship_and_inverse_ManyToOne_annotations