Using cascadeType.Merge duplicates my entity - spring

I have an entity "Employee" and a #Embeddable class RecycleBin. Now whenever a user deletes anything in the system the the entity class record is duplicated. I know it is because of the cascadeType.Merge i added in the RecycleBin class but if I remove cascadeType.Merge then the system crashes on delete operation giving a server error of "save transient before flushing". I have been stuck in this since two days and i am new to spring. If someone could please help me.
This is my Employee class.
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Version
private Long version;
private String fullName;
private String fatherName;
private String identityCardNo;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
private String placeOfBirth;
private String nationality;
private String email;
private String phoneNumber;
#Column(columnDefinition = "TEXT")
private String permanentResAddr;
#Column(columnDefinition = "TEXT")
private String presentResAddr;
#Enumerated(EnumType.STRING)
private MaritalStatus martialStatus;
#Enumerated(EnumType.STRING)
private Gender gender;
private String spouseName;
private String spouseOccupation;
private String spouseOrganization;
private String spouseDesignation;
private String numOfDependents;
private String languagesKnown;
private String salary;
private String bonus;
private String allowance;
private String stipend;
#ElementCollection(fetch = FetchType.EAGER)
#Column(name = "jobrole")
#Enumerated(EnumType.STRING)
private List<JobRole> jobRoles;
#Enumerated(EnumType.STRING)
private JobType jobType;
#ElementCollection(targetClass = Privilege.class, fetch = FetchType.LAZY)
#Column(name = "privilege")
#Enumerated(EnumType.STRING)
private List<Privilege> privileges;
// dep auto del
#OneToMany(mappedBy = "substituteTeacher")
private List<TimetableSubstitute> timetableSubstitutes;
// dep manul del
#OneToMany(mappedBy = "createdBy")
private List<SchemeOfWork> createdSchemeOfWorks;
// dep association del
#OneToMany(mappedBy = "createdBy")
private List<CommentBank> createdComments;
// dep manul del
#OneToMany(mappedBy = "teacher")
private List<BatchSubject> teacherSubjects;
// dep auto del
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "employee_campus", joinColumns = { #JoinColumn(name = "employee", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "branch", referencedColumnName = "id") })
private List<Campus> schoolCampuses;
// dep auto del
#OneToMany(mappedBy = "employee")
private List<CampusEmployeeAttendance> employeeBranchAttendanceList;
// dep auto del
#OneToMany(mappedBy = "employee")
private List<EmployeeAttendance> employeeDayAttendanceList;
// dep association del
#OneToMany(mappedBy = "createdByTeacher")
private List<ProfileForm> teacherCreateProfileForms;
// dep auto del
#ManyToMany(mappedBy = "employees")
private List<Announcement> announcements;
// dep auto del
#OneToMany(mappedBy = "employee")
private List<Notification> notification;
// dep auto del
#OneToOne
private UserLoginAccount employeeLoginAccount;
// dep manul del
#OneToMany(mappedBy = "batchTeacher")
private List<Batch> teacherBatches;
// dep manul del
#OneToOne(mappedBy = "schoolEmployee")
private Parent parent;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "employee_qualifications", joinColumns = #JoinColumn(name = "emp", referencedColumnName = "id"))
private List<Qualification> qualifications;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "employee_pre_employment", joinColumns = #JoinColumn(name = "emp", referencedColumnName = "id"))
private List<PreEmployment> preEmployments;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "employee_memberships", joinColumns = #JoinColumn(name = "emp", referencedColumnName = "id"))
private List<EmpMembership> memberships;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "employee_certificates", joinColumns = #JoinColumn(name = "emp", referencedColumnName = "id"))
private List<EmpCertificate> certificates;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "employee_references", joinColumns = #JoinColumn(name = "emp", referencedColumnName = "id"))
private List<EmpReference> references;
// dep auto del
#OneToMany(mappedBy = "employee", fetch = FetchType.LAZY)
private List<FileLibrary> empImages;
#Embedded
private RecycleBin recycleBin;
And this is my RecycleBin class.
#Embeddable
public class RecycleBin {
#Temporal(TemporalType.TIMESTAMP)
private Date deleteDate;
#ManyToOne(cascade= CascadeType.MERGE)
private Employee deletedBy;
#Enumerated(EnumType.STRING)
private RecycleBinStatus recycleBinStatus;

Related

Springboot ExampleMatcher always returns no result

I have the following entity and I'm trying to use ExampleMatcher for simple queries:
#Entity(name="UserAccount")
#Table(name = "useraccount", catalog = "useraccount")
#Data
public class UserAccount implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false, unique = true)
private String mail;
private String password;
private boolean isEnabled;
private Timestamp credentialExpire;
private boolean isAccountNonLocked;
private boolean isSuspended;
private Timestamp accountExpire;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#JoinTable(name = "user_to_privileges", catalog = "useraccount",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "privilege_id", referencedColumnName = "id", nullable = false)})
private Set<Privilege> privileges= new HashSet<>();
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#JoinTable(name = "user_to_organizations", catalog = "useraccount",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "organization_id", referencedColumnName = "id", nullable = false)})
private Set<Organization> organizations= new HashSet<>();
#OneToOne(mappedBy ="user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#PrimaryKeyJoinColumn
#Setter(AccessLevel.NONE)
private UserRegister register;
#OneToMany(mappedBy ="tokenId.user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
private Set<SecureToken> tokens = new HashSet<>();
#OneToOne(mappedBy ="user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#PrimaryKeyJoinColumn
private UserLogin login;
//all the methods omitted from brevity
}
I create the Example matcher as follows:
UserAccount account= new UserAccount();
account.setUsername("John");
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
Example<UserAccount> regExample = Example.of(account, matcher);
List<UserAccount> out = repository.findAll(regExample);
Consider that a user with username "John" exists, but the output is always empty, no matter what parameter I fill.
Edit: this helps to find the solution: Are there any possible ways to ignore all paths of JPA Example Matcher. There is no way to automatically ignore primitive fields when not used?
Edit: Notice that I want to find all the UserAccount containing the specified strings in the selected fields. With other entities the configuration of ExampleMatcher works.

How to send POST request with Many to many relationship in Spring Boot

Anyone have any ideas on how I could do postmapping for the Many-to-Many relationship? Getting the data works, but this is what I'm having trouble with
I tried using the "guide" but unfortunately I don't understand it very well yet
Here is my entities:
Album
#Entity
public class Album implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long id;
String name;
String artist;
String cover;
#ManyToMany(fetch = FetchType.LAZY, cascade =
{
CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.REFRESH,
CascadeType.PERSIST
})
#JoinTable( name = "user_albums",
joinColumns = #JoinColumn(name = "album_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "user_id", nullable = false)
)
#JsonBackReference
#OnDelete(action = OnDeleteAction.CASCADE)
private Set<User> users = new HashSet<>();
User:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(max = 20)
private String username;
#NotBlank
#Size(max = 50)
#Email
private String email;
#NotBlank
#Size(max = 120)
private String password;
#ManyToMany(fetch = FetchType.LAZY, cascade =
{
CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.REFRESH,
CascadeType.PERSIST
})
#JoinTable( name = "user_albums",
joinColumns = #JoinColumn(name = "user_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "album_id", nullable = false)
)
#OnDelete(action = OnDeleteAction.CASCADE)
private Set<Album> albums = new HashSet<>();
I tried it this way but it didn't work
#PostMapping("/users/mal/{userId}/album")
public ResponseEntity<Album> addAlbum(#PathVariable(value = "userId") Long userId, #RequestBody Album albumRequest, User userRequest) {
Album newMal = userRepo.findById(userId).map(user -> {
long albumId = userRequest.getId();
user.addAlbum(albumRequest);
return albumRepo.save(albumRequest);
}).orElseThrow(() -> new RuntimeException("Not found USER with id = " + userId));
return new ResponseEntity<>(newMal, HttpStatus.CREATED);

Why am i getting an infinite list with stack overflow?

Im making an bungalow reservation system but i cant get a list with an many to many relationship i keep getting an infinite list with stackoverflow error.
This worked find but happens when i added the many to many relationship.
Attraction Entity this contains a many to many relationship with
the visit entity
#Entity
#Table(name = "attraction")
public class Attraction {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#Column(name = "historical")
private Boolean historical;
#Column(name = "religious")
private Boolean religious;
#Column(name = "beaches")
private Boolean beaches;
#Column(name = "animal_sanc")
private Boolean animalSanc;
#Column(name = "hiking")
private Boolean hiking;
#Column(name = "forest")
private Boolean forest;
#Column(name = "parks")
private Boolean parks;
#Column(name = "lakes")
private Boolean lakes;
#ManyToOne
#JoinColumn(name = "bungalow_id")
private Bungalow bungalow;
#ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH})
#JoinTable(
name = "visit_has_attraction",
joinColumns = #JoinColumn(name = "attraction_id"),
inverseJoinColumns = #JoinColumn(name = "visit_id")
)
private List<Visit> visitList;
//Constructer, Getters and Setters
}
Visit entity
This is the other end of the many to many relationship
#Entity
#Table(name = "visit")
public class Visit {
#Id
#Column(name = "id")
private int id;
#Column(name = "date")
private Date date;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH})
#JoinTable(
name = "visit_has_attraction",
joinColumns = #JoinColumn(name = "visit_id"),
inverseJoinColumns = #JoinColumn(name = "attraction_id")
)
List<Attraction> attractions;
//Constructer, Getters and Setters
}
JPA Repository
public List<Attraction> findAttractionsByVisitList(Visit visit);
ER of the app
1
I added #JsonIgnore to one of the sides in many to many relationships and added #JsonBackReference to ManyToOne side and #JsonManagedReference to OneToMany side of all the one to many relationships.
#Entity
#Table(name = "attraction")
public class Attraction {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#Column(name = "historical")
private Boolean historical;
#Column(name = "religious")
private Boolean religious;
#Column(name = "beaches")
private Boolean beaches;
#Column(name = "animal_sanc")
private Boolean animalSanc;
#Column(name = "hiking")
private Boolean hiking;
#Column(name = "forest")
private Boolean forest;
#Column(name = "parks")
private Boolean parks;
#Column(name = "lakes")
private Boolean lakes;
#ManyToOne
#JoinColumn(name = "bungalow_id")
#JsonBackReference
private Bungalow bungalow;
#ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH})
#JoinTable(
name = "visit_has_attraction",
joinColumns = #JoinColumn(name = "attraction_id"),
inverseJoinColumns = #JoinColumn(name = "visit_id")
)
#JsonIgnore
private List<Visit> visitList;
//Constructer, Getters and Setters
}
Visit entity
This is the other end of the many to many relationship
#Entity
#Table(name = "visit")
public class Visit {
#Id
#Column(name = "id")
private int id;
#Column(name = "date")
private Date date;
#ManyToOne
#JoinColumn(name = "user_id")
#JsonBackReference
private User user;
#ManyToMany(cascade = {CascadeType.MERGE,CascadeType.REFRESH})
#JoinTable(
name = "visit_has_attraction",
joinColumns = #JoinColumn(name = "visit_id"),
inverseJoinColumns = #JoinColumn(name = "attraction_id")
)
List<Attraction> attractions;
//Constructer, Getters and Setters
}

Could not write JSON: Infinite recursion

I am getting StackOverflow recursion error when I run query in Postman or Browser .
When i run says:
.w.s.m.s.DefaultHandlerExceptionResolver : Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)
Here is the model classes :
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String title;
#NotNull
private String description;
#NotNull
private double price;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "category_id", nullable = false)
private Category category;
private boolean isSealed;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "currency_id", nullable = false)
private Currency currency;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Nullable
#OneToMany(mappedBy = "product",
cascade = CascadeType.ALL, orphanRemoval = true)
private List<Images> images;
private Date createdDate = new Date();
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "product")
private View view;
#OneToOne(fetch = FetchType.LAZY,cascade=CascadeType.ALL)
#JoinColumn(name="type_id")
private Type type;
private Long viewCount; }
#Entity public class Images{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String imagePath;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private Product product; }
#Entity public class User implements UserDetails, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String fullName;
#NotEmpty
#Email
#Column(unique = true)
private String email;
#NotNull
#Column(unique = true)
private int phoneNumber;
#NotEmpty
#Size(min = 5)
private String password;
private Date createAt = new Date();
#Nullable
private String picPath;
#Nullable
private String token;
#ManyToMany
#JoinTable(name = "user_roles", joinColumns = {#JoinColumn(
name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "role_id")})
private List<Role> roles;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "user")
private Product product;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "user")
private View view; }
#Entity
public class Currency{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String code;
private String currency;
private String region_country;
#OneToOne(mappedBy = "currency", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Product product; }
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String imagePath;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
mappedBy = "category")
private Product product;
#OneToMany(mappedBy = "category", fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private Set<Brand> brands; }
#Entity public class Brand {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "category_id", nullable = false)
private Category category; }
#Entity public class View {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "product_id", nullable = false)
private Product product; }
#Entity public class Type {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String name;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "type")
private Product product; }
#Id
private String role;
#ManyToMany(mappedBy = "roles")
private List<User> users;
}
More than one of your entities have each other in themselves.
For example, Product has an object of User, and User has an object of Product.
To solve this, you have to write
#JsonBackReference(value = "user-product")
private User user;
in the Product class,
and
#JsonManagedReference(value = "user-product")
private Product product;
In the user class.
Do it in every field and for every class that call each other.
Also, Check this out
JPA: Having lists on both ends without infinite loop
You have cycles in your data model. For example, Product holds Images and Images point back to Products.
This works in an object oriented world, because only pointer references are stored in those fields.
When serialized, however, the actual object is written out as json text. Your Product prints the Images object which in turn prints the Product object which again prints the Image object and so on.
You need to decide how you want to represent your json, map your database model into simple plain old java object and use this for serializations. These POJOs are often called View Model or Transport Objects.

springboot jpa combine two tables

I want to query data from two tables,
location field in Translation is a foreign key from id field of Location
#Entity
#Table(name = "Translation")
#Data
public class Translation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull private String language;
#NotNull private String name;
#NotNull private String description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "location", nullable = false, insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private Location location;
}
#Entity
#Table(name = "Location")
#Data
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull private String code;
#NotNull private String type;
private Double longitude;
private Double latitude;
#Column(name = "parent_id")
private Integer parentId;
#OneToMany(targetEntity = Translation.class, mappedBy="id", fetch = FetchType.EAGER)
private Set<Translation> translations;
}
————————————————————————————————————————
But when I use a query
#Query(
"SELECT new com.afkl.travel.exercise.model.RetrieveLocationResponse("
+ "loc.code, tran.name, loc.type, loc.latitude, loc.longitude, tran.description, loc.parentId)"
+ "FROM Location loc LEFT JOIN loc.translation tran")
List<RetrieveLocationResponse> fetchLeftJoin();
All the fields related to Translation is null, having no idea what happened
UPDATE
The following ones work for me.
#OneToMany(mappedBy = "location", cascade = CascadeType.ALL)
#JsonIgnore
private Set<Translation> translations;
#ManyToOne
#JoinColumn(name = "location")
private Location location;
try
#OneToMany(mappedBy = "location", cascade = CascadeType.ALL)
#JsonIgnore
private Set<Translation> translations;
#ManyToOne
#JoinColumn(name = "location")
private Location location;

Resources