How to fetch data from "Many to many" relationship table? JPA +SPRINGBOOT - java

I am wondering how to fetch the data from many to many relationship table that was autogenerated with JPA?
Database design
I wrote some query code that gives me exactly the data I would like to fetch. Although I am not sure how to translate it to the JPA:
SELECT id, first_name, last_name, phone_number, shift_id FROM
FROM users
RIGHT JOIN employees_enrolled
ON users.id = employees_enrolled.employee_id
Employee extends User.
User model:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name = "username", nullable = false)
private String username;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
Employee model:
#Entity(name = "employee")
public class Employee extends User implements Serializable {
private static final long serialVersionUID = 6529685098267757690L;
#JsonIgnore
#ManyToMany(mappedBy = "enrolledEmployees")
private List<Shift> shifts = new ArrayList<>();
#Column(name = "address", nullable = false)
private String address;
#Column(name = "hours", nullable = false)
private double hours;
public Employee() {}
public Employee(long id)
{
super(id);
}
public Employee(long id, String username, String password, String firstName, String lastName,
String email, String phoneNumber, String authLevel, String address, double hours) {
super(id, username, password, firstName, lastName, email, phoneNumber, authLevel);
this.address = address;
this.hours = hours;
}
Shift model:
#Entity
#Table(name = "shift")
public class Shift implements Serializable {
private static final long serialVersionUID = -7065683873804696266L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "employees_enrolled",
joinColumns = {#JoinColumn(name = "shift_id", referencedColumnName = "id",
insertable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "employee_id",
referencedColumnName = "id", insertable = false, updatable = false)})
private List<Employee> enrolledEmployees = new ArrayList<>();
private Long employee_id;
#Column(name = "description", nullable = false)
private String description;
#Column(name = "address", nullable = false)
private String address;

Related

Spring, Jpa : One To Many Error when the list contains values

I want to return a Profile Object in JSON containing a list of login details associated with a social network.
Everything works correctly when the "reseaux_sociaux" table is empty. For my status table I get my statuses in JSON format in my Profile object. However, when "reseaux_sociaux" contains values then I get the error below and my Profile object in JSON format is not returned...
(Logs)
https://cloudvyzor.com/logpad/?query&database=sandbox-7fb06b2c06f198a7c0e4ff7c74d659e0
Profil Class
#Entity
#Table(name = "Profil")
public class Profil {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "IdComptes", nullable = false)
private Comptes IdComptes;
private String Avatar;
private String Banniere;
private String Pseudo;
private String MailPro;
private String Bio;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(name = "Statut_Profil", joinColumns = #JoinColumn(referencedColumnName = "Id"),inverseJoinColumns = #JoinColumn(referencedColumnName ="Id"))
private List<Statut> Statut;
#OneToMany( mappedBy = "IdProfil")
#JsonManagedReference("id_profil")
private List<ReseauxSociaux> Reseaux;
public Profil(){}
public Profil(Long id, Comptes idComptes, String avatar, String banniere, String pseudo, String mailPro, String bio) {
Id = id;
IdComptes = idComptes;
Avatar = avatar;
Banniere = banniere;
Pseudo = pseudo;
MailPro = mailPro;
Bio = bio;
}
}
ReseauxSociaux Class
#Entity
#IdClass(ReseauxId.class)
public class ReseauxSociaux {
#Id
private int Id;
#Id
private Long IdProfil;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "IdProfil", insertable = false, updatable = false)
#JsonBackReference("id_profil")
private Profil Profil;
#ManyToOne
#JoinColumn(name = "Id", insertable = false, updatable = false)
#JsonBackReference("id")
private Reseau Reseau;
private String Identifiant;
private ReseauxSociaux()
{}
public ReseauxSociaux(int id, Long idProfil, String identifiant) {
Id = id;
IdProfil = idProfil;
Identifiant = identifiant;
}
}
Reseau class
#Entity
public class Reseau {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int Id;
private String Nom;
private String Couleur;
//I tried it with and without and it made no difference
#OneToMany( mappedBy = "Id")
#JsonManagedReference("id")
private List<ReseauxSociaux> Reseaux;
public Reseau(){}
public Reseau(int id, String nom, String couleur) {
Id = id;
Nom = nom;
Couleur = couleur;
}
//Get Set
}
Profil Controller
#RestController
#RequestMapping("/profil")
public class ProfilController {
private final ProfilRepository profilRepository;
public ProfilController(ProfilRepository profilRepository) {
this.profilRepository = profilRepository;
}
#PostMapping("/getprofil/{idCompte}")
Profil GetProfil(#PathVariable("idCompte") Long idCompte)
{
Profil profil= profilRepository.findProfilById(idCompte);
return profil;
}
}
I finally succeeded... The cause of the problem remains unclear but I have two hypotheses: the first is the use of capital letters on variable names; the second is the use of a list with the onetomany with the same name in two entities.
Profil class
#Entity
#Table(name = "Profil")
public class Profil {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "idComptes", nullable = false)
#JsonBackReference("id_comptes")
private Comptes idComptes;
private String avatar;
private String banniere;
private String pseudo;
private String mailPro;
private String bio;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(name = "statut_profil", joinColumns = #JoinColumn(referencedColumnName = "id"),inverseJoinColumns = #JoinColumn(referencedColumnName ="id"))
private List<Statut> statut;
#OneToMany( mappedBy = "idProfil")
#JsonManagedReference("id_profil")
private List<ReseauxSociaux> lstprofil;
public Profil(){}
public Profil(Long id, Comptes idComptes, String avatar, String banniere, String pseudo, String mailPro, String bio) {
this.id = id;
this.idComptes = idComptes;
this.avatar = avatar;
this.banniere = banniere;
this.pseudo = pseudo;
this.mailPro = mailPro;
this.bio = bio;
}
//get set
}
ReseauxSociaux class
#Entity
#IdClass(ReseauxId.class)
public class ReseauxSociaux {
#Id
private int id;
#ManyToOne
#JoinColumn(name = "id", insertable = false, updatable = false)
#JsonBackReference("id_reseau")
private Reseau reseau;
#Id
private Long idProfil;
#ManyToOne
#JoinColumn(name = "idProfil", insertable = false, updatable = false)
#JsonBackReference("id_profil")
private Profil profil;
private String identifiant;
private ReseauxSociaux()
{}
public ReseauxSociaux(int id, Reseau reseau, Long idProfil, String identifiant) {
this.id = id;
this.reseau = reseau;
this.idProfil = idProfil;
this.identifiant = identifiant;
}
}
Reseau class
#Entity
public class Reseau {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nom;
private String couleur;
#OneToMany( mappedBy = "id")
#JsonManagedReference("id_reseau")
private List<ReseauxSociaux> lstreseau;
public Reseau(){}
public Reseau(int id, String nom, String couleur) {
this.id = id;
this.nom = nom;
this.couleur = couleur;
}
}

Spring boot write predicate to retrieve user from given role list

I am trying to create a predicate to retrieve users having certain Role list (Role is a separate Table )
I have created predicate for other fields in User entity only unable to create the proper criteria for the above mentioned scenario.
below are the 2 entity classes
User:
#Entity
#Table(name = "user")
#Data
public class User implements Serializable {
public User() {
}
public User(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.email = user.getEmail();
this.fullName = user.getFullName();
this.address = user.getAddress();
this.contactNo = user.getContactNo();
this.enabled = user.isEnabled();
this.accountNonExpired = user.isAccountNonExpired();
this.credentialsNonExpired = user.isCredentialsNonExpired();
this.accountNonLocked = user.isAccountNonLocked();
this.roles = user.getRoles();
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username")
private String username;
#Column(name = "fullName")
private String fullName;
#Column(name = "contactNo")
private String contactNo;
#Column(name = "address")
private String address;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "enabled")
private boolean enabled;
#Column(name = "accountNonExpired")
private boolean accountNonExpired;
#Column(name = "credentialsNonExpired")
private boolean credentialsNonExpired;
#Column(name = "accountNonLocked")
private boolean accountNonLocked;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "role_user", joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> roles;
}
Role
#Entity
#Table(name = "role")
#Data
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "permission_role", joinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "id")}, inverseJoinColumns = {
#JoinColumn(name = "permission_id", referencedColumnName = "id")})
private List<Permission> permissions;
}
I have to use predicates No other option.
guide me how to write a predicate to get users who are having given Role list.
If you refer to Java 8 Predicate class:
Predicate<User> userPredicate = user -> user.getRoles().equals(roleListArg);
If you want a more complex predicate:
Predicate<User> userPredicate = user -> {
... your code here
};
Take care while comparing List objects like that. Should be better to check if the user has certains roles (user.getRoles().contains(role))
If you refer to JPA Specification:
public Specification<User> getUserByRoles(List<Role> roles) {
return (root, query, criteriaBuilder) => {
Join<Role, User> join = root.join("role");
//Return the condition you want to build, this is an example to get by role id
return criteriaBuilder.in(join.get(id), roles.get(0).getId());
}
}

How can I implement a JPQL query retrieving all the user having a specific type (implemented using a MANY TO MANY relation)?

I am working on a Spring Boot project and I am not so into Hibernate/JPA and I have the following doubt about how can I use it to perform the following query.
I have these 2 entity classes:
User: it contains records representing user on my portal:
#Entity
#Table(name = "portal_user")
#Getter
#Setter
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
#NotNull(message = "{NotNull.User.firstName.Validation}")
private String firstName;
#Column(name = "middle_name")
private String middleName;
#Column(name = "surname")
#NotNull(message = "{NotNull.User.surname.Validation}")
private String surname;
#Column(name = "sex")
#NotNull(message = "{NotNull.User.sex.Validation}")
private char sex;
#Column(name = "birthdate")
#NotNull(message = "{NotNull.User.birthdate.Validation}")
private Date birthdate;
#Column(name = "tax_code")
#NotNull(message = "{NotNull.User.taxCode.Validation}")
private String taxCode;
#Column(name = "e_mail")
#NotNull(message = "{NotNull.User.email.Validation}")
private String email;
//private String test;
#Column(name = "pswd")
#NotNull(message = "{NotNull.User.pswd.Validation}")
private String pswd;
#Column(name = "contact_number")
#NotNull(message = "{NotNull.User.contactNumber.Validation}")
private String contactNumber;
#Temporal(TemporalType.DATE)
#Column(name = "created_at")
private Date createdAt;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
#JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
#ManyToMany(cascade = { CascadeType.MERGE })
#JoinTable(
name = "portal_user_user_type",
joinColumns = { #JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { #JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.email = email;
this.pswd = pswd;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
}
}
Each user can be associated with one or more roles reppresented by this MANY TO MANY relationship:
#ManyToMany(cascade = { CascadeType.MERGE })
#JoinTable(
name = "portal_user_user_type",
joinColumns = { #JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { #JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
As you can see this field is associated to a DB table named portal_user_user_type that simply contains the PK of the user table and the PK of the user_type table represented by the following entity class:
#Entity
#Table(name = "user_type")
#Getter
#Setter
public class UserType implements Serializable {
private static final long serialVersionUID = 6904959949570501298L;
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "type_name")
private String typeName;
#Column(name = "description")
private String description;
//#OneToMany(mappedBy = "userType")
//#JsonManagedReference
//private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();
#ManyToMany(cascade = { CascadeType.MERGE })
#JoinTable(
name = "user_type_operation",
joinColumns = { #JoinColumn(name = "fk_user_type_id") },
inverseJoinColumns = { #JoinColumn(name = "fk_operation_id") }
)
Set<Operation> operations;
public UserType() {
super();
// TODO Auto-generated constructor stub
}
public UserType(String typeName, String description) {
super();
this.typeName = typeName;
this.description = description;
}
}
Now the previous class is mapping the user_type database typological table that can contains only a specific set of values. For example having typeName like ADMIN or AGENT or CLIENT.
Into my Spring Boot project I have this repository interface implementing JpaRepository interface:
public interface UsersRepository extends JpaRepository<User, Integer> {
User findByemail(String email);
}
At the moment it contains onlya query implemented using the "query by method name" tecnique.
Now I have to implement another more complex query based on the previous entity classes:
I have to retrieve all the User instance having a specific UserType.typeName value.
For example: retrieve all the User record having UserType.typeName equals to ADMIN.
Is it possible implement it using the query by method name style or is it better to use JPQL. In case how can I create a query like this? (also in JPQL is ok)
you can use #Query annotation in order to write your query or you can use findByUserTypes_TypeNameIn(List typeNameList) for a list of user type names or findByUserTypes_TypeName(String typeName) for a specific type name.

Hibernate one to many mapping annotation issue

I am new to Hibernate. I have two tables Team(parent) and Product(child) with TEAM_ID column as a relationship, each team will have multiple products and each product will have single team. I have created entity classes with #OneToMany mapping in Team class and #ManyToOne in Product class.
I need to coverup below scenarios,
To save both product and team when team is new
Save only product if the team is already available
When i am trying to save product it tries to save team again throws constraint error.
Please help.
Team:
#Entity
#Table(name = "TEAM")
public class Team implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="teamIdSeq",sequenceName="team_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="teamIdSeq")
#Column(name="TEAM_ID", updatable = false, nullable = false, unique = true)
private int teamId;
#Column(name="NAME", nullable = false, unique = true)
private String teamName;
#Column(name="DESCRIPTION", nullable = false)
private String teamDesc;
#Column(name="CONTACTS", nullable = false)
private String contacts;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="team", cascade = CascadeType.ALL)
private Set<Product> products;
//setters and getters
}
Product:
#Entity
#Table(name = "PRODUCT", uniqueConstraints = {#UniqueConstraint(columnNames = {"PRODUCT_ID", "TEAM_ID"})})
public class Product implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="productIdSeq", sequenceName="product_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="productIdSeq")
#Column(name="PRODUCT_ID", updatable = false, nullable = false)
private int productId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TEAM_ID")
private Team team;
#Column(name="NAME", nullable = false, unique = true)
private String productName;
#Column(name="DESCRIPTION", nullable = true)
private String productDesc;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="product")
private Set<Form> forms;
//setters and getters
}
DAO:
#Repository
#EnableTransactionManagement
public class KMDBDAOImpl implements KMDBDAO {
#Autowired
private SessionFactory sessionFactory;
public void addTeam(Team team) {
Product product = new Product(team, "BMA" + Math.random(), "UI Tool", "test",
1, new Date(), "test", new Date(), "test");
Set<Product> products = new HashSet<Product>();
products.add(product);
team.setProducts(products);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
}
public Team getTeam(String teamName) {
Query query = sessionFactory.getCurrentSession().createQuery("from Team where teamName = :name");
query.setString("name", "teamName");
return (query.list().size() > 0 ? (Team) query.list().get(0) : null);
}
The only time that you should set Product list on Team is when Team is a new entity. So:
Set<Product> products = new HashSet<Product>();
products.add(product);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
team.setProducts(products);
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
i give you some example code for one to many relationship please go through it and let me kn if some problem .... i have 2 tables 1.product 2.sku my condition is , one product have many sku's ...
Product.java
#LazyCollection(LazyCollectionOption.FALSE)
#ElementCollection(targetClass=Product.class)
#OneToMany(mappedBy="product" , cascade=CascadeType.MERGE)
private List<Sku> listSkuOrders = new ArrayList<>();
Sku.java
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = PRODUCT_ID , nullable = false)
private Product product;

Hibernate doesn't fill second table when one-to-one mapping is performed

I have small application which is responsible for saving data in database. I'm using Hibernate for this purpose. Below is my code:
User class
#Entity
#Table(name = "USERS")
#Transactional
public class User implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_ID")
private int userId;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "SURNAME")
private String surname;
#Column(name = "AGE")
private int age;
#Column(name = "EMAIL")
private String email;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
private Address address;
public User() {
}
public User(String firstName, String secondName, int age, String email) {
this.firstName = firstName;
this.surname = secondName;
this.age = age;
this.email = email;
}
// GETTERS/SETTERS
Address class
#Entity
#Table(name = "ADDRESS")
#Transactional
public class Address implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#GenericGenerator(name = "generator", strategy = "foreign", parameters = #Parameter(name = "property", value = "user"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "USER_ID", unique = true, nullable = false)
private int addressId;
#Column(name = "STREET")
private String street;
#Column(name = "STREET_NUMBER")
private String streetNumber;
#Column(name = "FLAT_NUMBER")
private String flatNumber;
#Column(name = "POSTAL_CODE")
private String postalCode;
#Column(name = "CITY")
private String city;
#Column(name = "COUNTRY")
private String country;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name = "USER_ID")
private User user;
public Address() {
}
public Address(String street, String streetNumber, String flatNumber, String postalCode, String city, String country) {
this.street = street;
this.streetNumber = streetNumber;
this.flatNumber = flatNumber;
this.postalCode = postalCode;
this.city = city;
this.country = country;
}
//GETTERS/SETTERS
And when I perform save() method which is responsible for saving data in this two tables only users table is filled up.
I found this solution Hibernate #OneToOne with Shared Primary Key(bidirectional). Dependent entity not persisted in DB.
but it doesn't work for me.
I'm using:
Hibernate 4.3.6.Final
Spring 4.3.6.RELEASE
Your Address class should be coded as follows (assuming that Address should be created with the same Id as the User where the id is generated):
#Id
#Column(name = "USER_ID", unique = true, nullable = false)
private int addressId;
#MapsId
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")
private User user;
During Persist
User u = new User();
// populate u fields
Address a = new Address();
a.setUser(u);
// populate a fields
session.persist(a);

Categories

Resources