Handle a ternary relationship using Javax annotation and Hibernate - java

I'm making an application that use a Rest Api to handle the communication between front and database.
Spring is used for the Java Api and Postgres as database.
The point is that I need a ternary relationship between three table. I explain myself, I have three table :
- user
- role
- project
Every user have a specific role depending on the project.
When I select a Project (in front), I need to display all the participants with their respective project.
Those are my classes :
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String email;
#NotNull
#Column(name = "last_name")
private String lastName;
#NotNull
#Column(name = "first_name")
private String firstName;
#NotNull
private String password;
private String image;
#Entity
#Table(name = "projects")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String name;
#NotNull
private Long version;
#NotNull
private Date date;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "user_profile_project", joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private List<User> participants;
#Entity
#Table(name = "profiles")
public class Profile {
private Long id;
private String name;
private Set<Permission> permissions = new HashSet<Permission>(0);
public Profile(){}
public Profile(String name) {
this.name = name;
}
public Profile(String name, Set<Permission> permissions) {
this.name = name;
this.permissions = permissions;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}

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

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.

#JsonIgnoreProperties JPA - Not ignoring properties

I am having a faq entity as below. Here createdBy field is having a manyToOne relationship with the user entity. Below joinColumns shows the association.
In the User entity, i have OneToMany relationship with UserRoles and UsersUnit which is EAGER load for User and not for faq. So i added #JsonIgnoreProperties
for UsersUnit and UsersRole and the corresponding User entity is shown below.
#Entity
#Table(name = "FAQ", catalog="abc")
public class Faq implements Serializable {
public Faq() {
super();
}
#Column(name = "CREATE_DATE")
private Timestamp createDate;
#Where(clause = "DELETE_DATE is null")
#Column(name = "DELETE_DATE")
private Timestamp deleteDate;
#Column(name = "DELETED_BY")
private BigDecimal deletedBy;
#Column(name = "DOC_BLOB", nullable = false)
#JsonIgnore
private byte[] docBlob;
#Column(name = "DOC_NAME", nullable = false, length = 100)
private String docName;
#Id
private BigDecimal id;
#Column(name = "ORDER_BY")
private BigDecimal orderBy;
#Column(name = "UPDATE_DATE")
private Timestamp updateDate;
#Column(name = "UPDATED_BY")
private BigDecimal updatedBy;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="created_by", referencedColumnName="id")
})
private User faqCreatedBy;
}
User entity:
#Entity
#Table(name = "USERS", catalog="abc")
#JsonInclude(Include.NON_NULL)
public class User extends EntityLog{
private BigDecimal id;
private BigDecimal edipi;
private String firstname;
private String lastname;
private String email;
..///
private Set<UsersRoles> userRoles;
private Set<UsersUnit> usersUnit;
#Id
#Column(name="id")
public BigDecimal getId() {
return id;
}
...///
#Column
#JsonIgnoreProperties({ "faqCreatedBy" })
#OneToMany(fetch = FetchType.EAGER,mappedBy = "user",cascade = {CascadeType.ALL})
#JsonManagedReference
public Set<UsersRoles> getUserRoles() {
return userRoles;
}
...///
#Column
#JsonIgnoreProperties({ "faqCreatedBy" })
#OneToMany(fetch = FetchType.EAGER,mappedBy = "user",cascade = {CascadeType.ALL})
#JsonManagedReference
public Set<UsersUnit> getUsersUnit() {
return usersUnit;
}
////...
}
With this change I am expecting the faq to load with User entity but I am not execting UsersRoles and UsersUnit to load.
But that is not what i see. When faq loads it loads User and UsersRoles and UsersUnit. I am using Spring JPA fyi. Any leads what is wrong ? Appreciate any inputs.

Error accessing field (using Hibernate/JPA)

I'm having this error
Error accessing field [private java.lang.Integer
fearx.projects.animal.finder.api.entity.LoginEntity.id] by reflection
for persistent property
[fearx.projects.animal.finder.api.entity.LoginEntity#id] : 2; nested
exception is
org.hibernate.property.access.spi.PropertyAccessException: Error
accessing field [private java.lang.Integer
fearx.projects.animal.finder.api.entity.LoginEntity.id] by reflection
for persistent property
[fearx.projects.animal.finder.api.entity.LoginEntity#id] : 2
While I try to do this:
public void registerUser(OwnerEntity body) {
ownerRepository.save(body);
loginRepository.save(new LoginEntity(body.getEmail(), body.getPassword()));
LoginEntity loginEntity = loginRepository.findByEmail(body.getEmail());
OwnerEntity ownerEntity = ownerRepository.findByEmail(body.getEmail());
ownerLoginRepository.save(new OwnerLoginEntity(loginEntity.getId(),ownerEntity.getId()));
}
My entitys:
#Entity(name = "owner_login")
#Data
public class OwnerLoginEntity {
#Id
#GeneratedValue
private Integer id;
#ManyToOne(targetEntity = LoginEntity.class)
#JoinColumn(name = "id_login", referencedColumnName = "id")
private Integer login;
#ManyToOne(targetEntity = OwnerEntity.class)
#JoinColumn(name = "id_owner", referencedColumnName = "id")
private Integer owner;
public OwnerLoginEntity(Integer login, Integer owner) {
this.login = login;
this.owner = owner;
}
}
public class OwnerEntity {
#Id
#GeneratedValue
private Integer id;
#Column
private String name;
#Column
private String email;
#Column
private String phone;
#Column
private String password;
#ManyToOne(targetEntity = LostPetEntity.class)
#JoinColumn(name = "id_pet", referencedColumnName = "id")
private Integer id_pet;
}
#Entity(name = "login")
#Data
public class LoginEntity {
#Id
#GeneratedValue
private Integer id;
#Column(unique = true, nullable = false)
private String email;
#Column
private String password;
public LoginEntity(String email, String password) {
this.email = email;
this.password = password;
}
public LoginEntity() {
}
}
O don't know what database you have, but try to change the approach of GeneratedValue like this:
#Entity(name = "owner_login")
#Data
public class OwnerLoginEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#ManyToOne
private LoginEntity login;
#ManyToOne
private OwnerEntity owner;
public OwnerLoginEntity(LoginEntity login, OwnerEntity owner) {
this.login = login;
this.owner = owner;
}
}
Then you can call ownerLoginRepository.save(new OwnerLoginEntity(loginEntity, ownerEntity));

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