How to insert data in ManyToMany Rest Api - spring-boot

I can not find the way to insert data using ManyToMany in spring boot. Can anyone please suggest me how to save data using M-To-M in spring boot and hibernate.
Here down is my code.
Entity
#Entity
#Table(name = "user_master")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer user_id;
private String name;
#JsonManagedReference
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "users_roles", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = {
#JoinColumn(name = "role_id") })
private Set<Roles> roles;
// constructor and getter/setter
}
#Entity
#Table(name = "role_master")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer role_id;
private String name;
#JsonBackReference
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "roles")
private Set<Users> users;
// constructor and getter/setter
}
service
#Override
public Set<Users> addAddressPerson(Set<Users> users) {
for(User user: users) {
for(Roles roles: user.getRoles()) {
roles.getUsers().add(user); // problem is in here
}
}
return users.stream().map(userRepo::save).collect(Collectors.toSet());
}
Postman
[
{
"name": "Michael",
"roles": [
{
"name": "Project Manager"
},
{
"name": "Software Developer"
}
]
}
]
Error
"message": "Cannot invoke "java.util.Set.add(Object)" because the return value of "com.rest.RestApiPojo.Entity.Roles.getUsers()" is null"

try
#Override
public Set<Users> addAddressPerson(List<Users> users) {
for(User user: users) {
for(Roles roles: user.getRoles()) {
roles.getUsers().add(user);
}
}
return users.stream().map(UserRepo::save).collect(Collectors.toSet());
}
and
#Entity
#Table(name = "user_master")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer user_id;
private String name;
#JsonManagedReference
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "users_roles", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = {
#JoinColumn(name = "role_id") })
private Set<Roles> roles = new HashSet<>();
// constructor and getter/setter
}
#Entity
#Table(name = "role_master")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer role_id;
private String name;
#JsonBackReference
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "roles")
private Set<Users> users = new HashSet<>();
// constructor and getter/setter
}

Related

jpa - list OneToMany not saved

I have the below room entity which has many disponibilities, when i add a room with a list of disponibilities, the room is saved but the list is not. what am i missing in the relationship ?
#Entity
public class RoomEntity {
#Id
private String classRoomId;
private String label;
#OneToMany(mappedBy = "room", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<DisponibilityEntity> disponibilities;
public void addDisponibilities(List<DisponibilityEntity> disponibilityEntities) {
if (CollectionUtils.isEmpty(disponibilities)) {
disponibilities = new ArrayList<>();
}
disponibilities.addAll(disponibilityEntities);
disponibilityEntities.forEach(item -> item.setRoom(this));
}
}
#Entity
public class DisponibilityEntity {
#Id
private String disponibilityId;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_room")
private RoomEntity room;
}
roomEntity.addDisponibilities(classRoomEntity.getDisponibilities());
roomRepository.save(roomEntity);

Hibernate deletion referential integrity constraint violation on many to many association

I am trying to use Hibernate to remove an entity however I get an error: Cannot delete or update a parent row: a foreign key constraint fails
The setup is that I have an abstract class A and two classes (B and C) which extend A. B contains a list of C's (unidirectional relationship). And there is a function to delete A by its ID.
Note: Stuff has been removed for brevity.
#Entity
public class B extends A {
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
joinColumns = #JoinColumn(name = "B_A_id"),
inverseJoinColumns = #JoinColumn(name = "C_A_id"))
List<C> cList;
}
#Entity
public class C extends A {
(no reference to B)
}
The issue is that when the deleteAByFixedId is called where A is a C, it tries to delete the C before it deletes the B which references it and therefore I get a foreign key constraint failure.
What am I doing wrong?
The answer will still be updated.
Links:
The best way to use the #ManyToMany annotation with JPA and Hibernate
Hibernate Inheritance Mapping
#ManyToMany
Unidirectional example:
User.java
#Entity
public class User {
#Id
#GeneratedValue
#Column(name = "user_id")
private long id;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
public void addRoles(Role role) {
roles.add(role);
}
public void removeRoles(Role role) {
roles.remove(role);
}
}
Role.java
#Entity
public class Role {
#Id
#GeneratedValue
#Column(name = "role_id")
private int id;
#Column(name = "role")
private String role;
}
Bidirectional example:
Trader.java:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#ToString(exclude = "stockmarkets")
#Table(name = "trader")
public class Trader {
#Id
#GeneratedValue
#Column(name = "trader_id")
private Long id;
#Column(name = "trader_name")
private String traderName;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "TRADER_STOCKMARKET",
joinColumns = { #JoinColumn(name = "trader_id") },
inverseJoinColumns = { #JoinColumn(name = "stockmarket_id") })
private Set<Stockmarket> stockmarkets = new HashSet<>();
/*
We need to add methods below to make everything work correctly
*/
public void addStockmarket(Stockmarket stockmarket) {
stockmarkets.add(stockmarket);
stockmarket.getTraders().add(this);
}
public void removeStockmarket(Stockmarket stockmarket) {
stockmarkets.remove(stockmarket);
stockmarket.getTraders().remove(this);
}
}
Stockmarket.java
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#ToString(exclude = "traders")
#Table(name = "stockmarket")
public class Stockmarket{
#Id
#GeneratedValue
#Column(name = "stockmarket_id")
private Long id;
#Column(name = "stockmarket_name")
private String stockmarketName;
#ManyToMany(mappedBy="stockmarkets")
private Set<Trader> traders = new HashSet<>();
/*
We need to add methods below to make everything work correctly
*/
public void addTrader(Trader trader) {
traders.add(trader);
trader.getStockmarkets().add(this);
}
public void removeTrader(Trader trader) {
traders.remove(trader);
trader.getStockmarkets().remove(this);
}
}

JPA - Issue with OneToOne relationship when two foreign keys are primary key to entity

Two foreign keys act as primary key in entity for OneToOne, I'm getting error "Provided id of the wrong type for class ....."
When I tried to POST data, It's getting inserted correctly but GET is not working.
If I change OneToOne to OneToMany it is working for POST & GET both.
Request:
{
"items": [
{
"applicant": {
"guests": [
{
"seqNumber": 1,
"name": "name",
"gender": "gender"
}
]
}
}
]
}
Back Reference:
reservation.getItems().forEach(i -> {
i.setReservation(reservation);
i.getApplicant().setItem(i);
i.getApplicant().getGuests().forEach(g -> g.setApplicant(i.getApplicant()));
});
Reservation Entity:
#Entity
#Getter
#Setter
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_RESERVATION", nullable = false, updatable = false)
private String reservationId;
#OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Item> items = new HashSet<>();
}
Item Entity:
#Entity
#Getter
#Setter
#IdClass(Item.ItemKey.class)
public class Item {
#Id
#Column(name = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
private long itemReservationId;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false)
#JsonBackReference
private Reservation reservation;
#OneToOne(mappedBy = "item", cascade = CascadeType.ALL)
#JsonManagedReference
private Applicant applicant;
#Data
static class ItemKey implements Serializable {
private Reservation reservation;
private long itemReservationId;
}
}
Applicant Entity:
#Entity
#Getter
#Setter
#IdClass(Applicant.ApplicantKey.class)
public class Applicant {
#Id
#OneToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Item item;
#OneToMany(mappedBy = "applicant", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Guest> guests = new HashSet<>();
#Data
static class ApplicantKey implements Serializable {
private Item item;
}
}
Guest Entity:
#Entity
#Getter
#Setter
#IdClass(Guest.GuestKey.class)
public class Guest {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Applicant applicant;
#Id
#Column(name = "S_NUMBER", nullable = false, updatable = false)
private Short seqNumber;
#Column(name = "N_NAME")
private String name;
#Column(name = "CD_GENDER")
private String gender;
#Data
static class GuestKey implements Serializable {
private Applicant applicant;
private Short seqNumber;
}
}
Expected output must be same as Request but getting error " ... Provided id of the wrong type for class ..."
Here is the code.

access many to many relation in spring

I have a class called Tag:
#Entity
#Table(name = "tags")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
...
}
And a class called Post
#Entity
#Table(name = "posts")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "post_tags",
joinColumns = { #JoinColumn(name = "post_id") },
inverseJoinColumns = { #JoinColumn(name = "tag_id") })
private Set<Tag> tags = new HashSet<>();
...
}
It creates another table named post_tags.
How can I write a Controller to access that table as it is not similar a repository?
Is there more easy and convenient way to implement ManyToMany relationship ?
My pom.xml
You don't need to access that relation table manually. You can load load all Tag entities, and then load all the referenced Post entities.
The relation table is enterily managed by your ORM frameork.
But, if you still want to access the relation table, you can use native queries in your Spring Data JPA repository, e.g.
#Query(value="select post_id, tag_id from post_tags", nativeQuery=true)
List<PostTag> loadPostTags();
PostTag class is not a jpa-managed entity and must match the structue of the returned table:
public class PostTag {
private long postId;
private long tagId;
// getter, setter
}
Use this way
#Entity
#Table(name = "tags")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "post_tags",
joinColumns = { #JoinColumn(name = "id") },
inverseJoinColumns = { #JoinColumn(name = "post_id") })
private Set<Post> posts = new HashSet<>();
...
}
#Entity
#Table(name = "posts")
public class Post {
#Id
#Column(name = "post_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postId;
...
}

object references an unsaved transient instance - Spring, JPA Hibernate

Here is the code:
#Entity
public class PortalUser {
#NotNull
#OneToMany(mappedBy = "portalUser", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<PortalUserOrganisation> portalUserOrganisations;
#NotNull
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "portalUser", orphanRemoval = true)
private Set<UserRole> userRoles = new HashSet<UserRole>();
}
#Entity
public class PortalUserOrganisation {
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private PortalUser portalUser;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ORGANISATION_ID", referencedColumnName = "ID")
private Organisation organisation;
}
#Entity
public class Organisation {
#OneToMany(mappedBy = "organisation", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private Set<PortalUserOrganisation> portalUserOrganisations;
}
#Entity
public class UserRole {
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private PortalUser portalUser;
#NotNull
#ManyToOne(fetch = FetchType.LAZY, optional=true)
#JoinColumn(name = "ROLE_ID", referencedColumnName = "ID")
private RoleLookup roleLookup;
}
#Entity
public class RoleLookup extends AbstractLookupEntity {
#OneToMany(mappedBy = "roleLookup", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private Set<UserRole> userRoles = new HashSet<UserRole>();
}
Code to Create a User:
#Transactional
saveUser(userObj)
PortalUser portalUser = new PortalUser;
portalUser.setStatus(status);
PortalUserOrganisation userOrganisation = null;
for (OrganisationsDto dto : organisationsList()) {
userOrganisation = new PortalUserOrganisation();
userOrganisation.setOrganisation(organisationRepository.findOne(dto.getId()));
userOrganisation.setPortalUser(portalUser);
userOrganisation.setCreatedUpdatedBy(context.getName());
userOrganisation.setCreatedUpdatedDate(createUpdateDate);
userOrganisation.setAction(portalUser.getAction());
userOrganisation.setStatus(portalUser.getStatus());
userOrganisation.setActive(true);
portalUser.getPortalUserOrganisation().add(userOrganisation);
}
UserRole userRole = null;
for (RoleLookupDto dto : portalUserDto.getUserRoles()) {
userRole = new UserRole();
userRole.setPortalUser(portalUser);
userRole.setRoleLookup(roleLookupRepository.findOne(dto.getId()));
userRole.setCreatedUpdatedBy(context.getName());
userRole.setCreatedUpdatedDate(createUpdateDate);
userRole.setAction(portalUser.getAction());
userRole.setStatus(portalUser.getStatus());
userRole.setActive(true);
portalUser.getUserRole().add(userRole);
}
portalUser.setActive(false);
portalUser = portalUserRepository.save(portalUser);
return portalUser;
I have see so many post, but this has not solved my issue. Any help is appreciated. Here the RoleLookup is a static table. Here is the exception:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.commerzbank.clearing.ccp.domain.UserRole.roleLookup -> com.commerzbank.clearing.ccp.domain.RoleLookup; nested exception is java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.commerzbank.clearing.ccp.domain.UserRole.roleLookup -> com.commerzbank.clearing.ccp.domain.RoleLookup
You should set a cascade = "save-update " for many-to-one side.

Resources