Delete Operation on Embedded Object Spring JPA - spring

I Have below Entities :
#Entity(name = "USRGRP_MAP")
public class UserGroupMapping {
#Id
#Column(name = "USRGRP_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GRP_MAP_SEQ")
#SequenceGenerator(sequenceName = "usrgrp_map_seq",allocationSize = 1,name = "USER_GRP_MAP_SEQ")
private Long mappingId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "USR_GRP_ID", referencedColumnName = "USR_GRP_ID")
private UserGroup group;
#Column(name = "USR_USRGRP_ACT")
private String userGroupAct;
getter/setters
}
#Entity(name = "USER")
public class User {
#Id
#Column(name = "USER_ID")
private Long userId;
#Column(name = "LOGIN_ID")
private String userName;
getter/setters
}
#Entity(name = "USR_GRP")
public class UserGroup {
#Id
#Column(name = "USR_GRP_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GRP_SEQ")
#SequenceGenerator(sequenceName = "usr_grp_seq",allocationSize = 1,name = "USER_GRP_SEQ")
private long groupId;
#Column(name = "GRP_NM")
private String groupName;
#Column(name = "GRP_DESC")
private String groupDesc;
getter/setters
}
UserGroupMapping contains has many to one relationship with both user and group.
Now I want to do CRUD operation on UserGroupMapping for that I have created repository as below:
public interface UserGroupMappingRepository extends JpaRepository<UserGroupMapping, Long> {
List<UserGroupMapping> findByGroup(UserGroup group);
List<UserGroupMapping> findByUser(User user);
}
Now I want to write delete operation(for particular user and group) on UserGroupMapping without deleting any entry in USER and USR_GRP table , Just need to remove entry from USRGRP_MAP table.
I am trying to achieve it using native query:
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
Facing Exception Invalid SQL grammar, although query work fine in sql developer.
Below is my service class:
#Service
public class UserGroupMappingServiceImpl implements UserGroupMappingService{
#Autowired
private UserGroupMappingRepository repository;
#Override
public void deleteUserGroupMapping(Long userId, Long groupId) {
repository.deleteUserGroupMappingByUserAndGroup(userId,groupId);
}
}
Could anyone suggest correct way to delete entry from UserGroupMapping without deleting user and group ?
Below is USRGRP_MAP table:
USRGRP_ID USER_ID USR_USRGRP_ID USR_USRGRP_ACT
------------- ---------- ------------- -
41 306106 41 Y
14 108527 14 Y
8 295597 8 N
10 296518 10 Y
11 295597 11 Y
Thanks in advance .

Try to change
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
To this:
#Modifying
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
Cheers
~Emil

Related

java.sql.SQLException: Field 'id' doesn't have a default value with Many to Many relation

I am trying to do Many to many relation. I have UserEntity and NoteEntity.
Note can be shared to many users, and user can have many notes from other users.
public class NoteEntity {
#Id
#Column(name = "id_note", nullable = false)
private String id;
#ManyToMany(mappedBy = "sharedToUserNotes")
private Set<UserEntity> receivers = new HashSet<>();
}
public class UserEntity implements UserDetails {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
#Column(name = "id_user")
private String id;
#ManyToMany(
cascade = {
CascadeType.MERGE, CascadeType.PERSIST
})
#JoinTable(name = "shared_notes",
joinColumns = { #JoinColumn(name = "id_user") },
inverseJoinColumns = { #JoinColumn(name = "id_note") })
private Set<NoteEntity> sharedToUserNotes = new HashSet<>();
and when I am trying add note to set of notes and next save it:
public void addNoteToSharedToUserNotes(ShareForm shareForm) throws ValueNotFoundException{
NoteEntity note = noteService.getNoteById(shareForm.getIdNote());
UserEntity user = userService.getUserByLogin(shareForm.getUserLogin());
user.getSharedToUserNotes().add(note);
userEntityRepository.saveAndFlush(user);
}
. I'm getting error
java.sql.SQLException: Field 'id' doesn't have a default value
I think it is about additional table "shared_notes", becouse it has columns like: id, id_note, id_user and I can not find how to set value of that id.

How can I retrieve all the children of a record in this Hibernate #ManyToOne relation?

I am working on a Spring Boot project using Spring Data JPA and Hibernate mapping. I have the following doubt about how can I implement the following query.
I have an User entity class like this:
#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 Integer 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;
#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;
#Column(name = "is_active")
private boolean is_active;
#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;
#ManyToOne(fetch = FetchType.EAGER)
#JsonProperty("subagent")
private User parent;
public User() {
super();
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
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;
this.is_active = is_active;
}
}
The instances of this class represents users of my system. An user can have a single specific parent (the concept is similar to that of a referral: an user can bring another user in the system). This is handled by this ManyToOne recursive relationship:
#ManyToOne(fetch = FetchType.EAGER)
#JsonProperty("subagent")
private User parent;
Basically an user contains is parent (who bring him\her into the platform). It works fine. So retrieving an user I can easily retrieve the information of who is its parent (it is contained into the retrieved User object).
Now I need to implement the inverse behavior: I have to define a "query" that starting from a parent retrieve all its children.
The previous User entity class maps the following DB table:
The highlighter parent_id contains the FK that define this recursive relationship. So it contains the PK of another user that is the parent.
I have this UserRepository repository interface (it extents the JpaRepository interface)
public interface UsersRepository extends JpaRepository<User, Integer> {
User findByemail(String email);
List<User> findByUserTypes_TypeName(String typeName);
}
As you can see I am using a "query by method" style. Is it possiblem implement a behavior like this using "query by method" style? (in case also JPQL could be fine)
You can do this
List<User> findByParent_Id(Integer id);
Or you can do this
#Query("SELECT u FROM User u WHERE u.id = ?1")
List<User> getReferredUsers(Integer id);
The relationship between the user and the parent is unidirectional in the given code. By making it bidirectional, it is easy to query the data in either ways.
Refer to below code to make it bidirectional. Also ensure the relevant FetchType to avoid the performance risk. Here FetchType.LAZY is used for one to many association so it queries the data using the proxy reference when needed.
#ManyToOne(fetch = FetchType.EAGER)
#JsonProperty("subagent")
#JsonBackReference
private User parent;
#JsonManagedReference
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
private Set<User> userSet = new HashSet<>();
Child entities are fetched only when parent.getUserSet is used because of the FetchType.Lazy
public Set<User> getUsers(int id) {
User parent = userRepository.getById(id);
return parent.getUserSet();
}

Hibernate - Spring - ConstraintViolationException - UniqueConstraint

I'm trying to make some fixtures for my Profile model but every time I'm trying to save it "again" after I did an update, I get this message:
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
This is my Profile class:
#Entity
#Data
#Builder
#ToString(of = {"birthday", "discordId", "description", "spokenLanguages"})
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
public class Profile implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idProfile;
private Date birthday;
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
private String description;
#ElementCollection(fetch = FetchType.EAGER)
private Set<String> spokenLanguages = new LinkedHashSet<String>();
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER)
private Set<ProfileGame> profileGames = new LinkedHashSet<>();
#OneToOne(mappedBy = "profile", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
private User user;
#ManyToOne
private TimeSlot timeSlot;
}
Here is the call:
#Order(7)
#Test
void fillProfileGame() {
List<Profile> profileList = this.profileRepository.findAll();
for (Profile profile : profileList) {
List<Game> gameList = this.gameRepository.findAll();
Collections.shuffle(gameList);
int rndNbGame = new Random().ints(1, 5).findFirst().getAsInt();
for (int i = 1; i <= rndNbGame; i++) {
int rndLevel = new Random().ints(1, 100).findFirst().getAsInt();
int rndRanking = new Random().ints(1, 3000).findFirst().getAsInt();
Game rndGame = gameList.get(0);
gameList.remove(0);
ProfileGame profileGames = new ProfileGame(profile, rndGame, "level-" + rndLevel,
"ranking-" + rndRanking);
this.profileGameRepository.save(profileGames);
this.gameRepository.save(rndGame);
}
this.profileRepository.save(profile);
}
}
So what I understand is that Hibernate won't let me update this object because it has a unique contraint field ?
How do we proceed when we want a field to be unique and still being able to update other fields ?
From the code snippet, what I see is that there are some unique constraints applied on the column 'discordId'.
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
and
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
As you can see, there is a parameter 'updatable' which is set to false. Therefore, when you are trying to update an already existing object, hibernate is throwing UniqueConstraintViolationException.
To fix this, set 'updatable=true' or remove it altogether and it should work fine.
#Column(name="discordId", insertable=true, updatable=true)
private String discordId;

JPA Join query inside #Query

i have three model class there are - User, Menu, Sub-menu.
#Data
#Entity
#Table(name = "CBR_USER")
public class User {
#Id
#GeneratedValue
#Column(name = "CBR_USER_ID")
private Integer cbrUserId;
#Column(name = "LOG_IN_ID")
private String logInId;
private String userId;
private String password;
#Column(name = "FULL_NAME")
private String FULL_NAME;
private String EMAIL;
private String PHONE;
private Integer ROLE_ID;
private String DESIGNATION;
private String branchId;
private Integer IS_VALID;
#ManyToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "Conf_menu_Access", joinColumns = #JoinColumn(name = "CBR_USER_ID"), inverseJoinColumns = #JoinColumn(name = "id"))
private List<Menu> menuList;
}
Menu class is :
#Data
#Entity
#Table(name = "CONF_MENU")
public class Menu {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_menu")
#SequenceGenerator(name = "seq_menu", sequenceName = "seq_menu", allocationSize = 1)
private Integer id;
private String name;
private String url;
private Integer accessBy;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "menuId")
private List<SubMenu> menuList;
}
and sub-menu class is
#Data
#Entity
#Table(name = "conf_sub_menu")
public class SubMenu {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_sub_menu")
#SequenceGenerator(name = "seq_sub_menu", sequenceName = "seq_sub_menu", allocationSize = 1)
private Integer id;
#Column(name = "MENU_ID")
private Integer menuId;
private String name;
private String url;
}
after compile my code it's generate another mapping table name as
Conf_menu_Access
this table map user access able menu , it's define in User class.
now i need to implement a sql query which is
SELECT ID ,NAME,
CASE
WHEN (SELECT ID FROM CONF_MENU_ACCESS WHERE CBR_USER_ID = 150 AND ID = CMA.ID )>0 THEN 1
ELSE 0
END AS ACCESSBY
FROM CONF_MENU CMA ORDER BY ID ASC
i want to write this query inside #Query tag, any one can help me how to do this......
You can use
#Query(value = "SELECT ID ,NAME,
CASE
WHEN (SELECT ID FROM CONF_MENU_ACCESS WHERE CBR_USER_ID = 150 AND ID = CMA.ID )>0
THEN 1 ELSE 0
END AS ACCESSBY
FROM CONF_MENU CMA ORDER BY ID ASC", nativeQuery = true)
It might be that column name which you are using it should match the column name in the database and the error which is coming is may be that the column name you are passing is of entity field.

QuerySyntaxException in Spring Data JPA custom query

I have a Entity:
#Entity
#Table(name = "story", schema = "")
#Data
public class Story implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sID", unique = true, nullable = false)
private Long sID;
#Column(name = "vnName", nullable = false)
private String vnName;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd-MM-yyyy HH:mm:ss")
#Column(name = "sUpdate", length = 19)
private Date sUpdate;
}
And:
#Entity
#Table(name = "chapter", schema = "")
#Data
public class Chapter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "chID", unique = true, nullable = false)
private Long chID;
#Column(name = "chName", nullable = false)
private String chName;
#JoinColumn(name = "sID", referencedColumnName = "sID")
#ManyToOne(fetch = FetchType.LAZY)
private Story story;
}
I had created custom pojo to get the latest update story with the latest chapter:
#Data
public class NewStory{
private Story story;
private Chapter chapter;
}
but when I get list :
#Repository
public interface StoryRepository extends CrudRepository<Story, Long> {
#Query(value="SELECT NEW com.apt.truyenmvc.entity.NewStory(s as newstory, c as newchapter)"
+ " FROM story s LEFT JOIN (SELECT * FROM Chapter c INNER JOIN "
+ " (SELECT MAX(c.chID) AS chapterID FROM Story s LEFT JOIN Chapter c ON s.sID = c.sID GROUP BY s.sID) d"
+ " ON c.chID = d.chapterID) c ON s.sID = c.sID order by s.sUpdate desc")
public List<NewStory> getTopView();
}
Error:
Warning error: org.hibernate.hql.internal.ast.QuerySyntaxException: story is not mapped.
Who could help me fix it? Or could it be done in a different way?
The error is pretty self explainatory. And its just a typo in your query. You are using story. And obviously thats not mapped as an Entity.
Fix it to Story

Resources