I have created update method in spring boot. It creates new record instead of update the record.
Tried code:
controller:
#PutMapping("update/{id}")
public Users updateUser(#PathVariable Integer id, #RequestBody Users user) {
user.setFname(user.getFname());
user.setLname(user.getLname());
user.setAddress(user.getAddress());
user.setTelno(user.getTelno());
return serveiceClass.updateUserbyId(id, user);
}
service:
public Users updateUserbyId(Integer id, Users users) {
return repositoryInterface.save(users);
}
How can I solve this problem?
You are not checking if user is present or not and you creating new record by calling save method. save method always insert new row if id in given object is not present in DB, in your case user is having id 0 I guess, thats why it is inserting new record. You need to fetch the User from given id and update the existing record in DB.
Create one more method in service class
public Users getUserById(Integer id) {
return repositoryInterface.findById(id).orElse(null);
}
And then..
#PutMapping("update/{id}")
public Users updateUser(#PathVariable Integer id, #RequestBody Users user) {
Users userExisting = serveiceClass.getUserById(id);
if(userExisting == null){
throw Exception("User Not Found");
}
userExisting.setFname(user.getFname());
userExisting.setLname(user.getLname());
userExisting.setAddress(user.getAddress());
userExisting.setTelno(user.getTelno());
return serveiceClass.updateUserbyId(userExisting);
}
Related
Here's my spring endpoint:
#DeleteMapping("/{id}")
public ResponseEntity<Package> deletePackage(JwtAuthenticationToken principal,
#PathVariable Long id) {
Package parcel = packageService.retrievePackage(id);
checkResourceBelongsToUser(principal, parcel);
return new ResponseEntity<>(packageService.deletePackage(parcel), HttpStatus.ACCEPTED);
}
And here's my current way of checking if the current resource the user is trying to update/delete belongs to the user:
private void checkResourceBelongsToUser(Address address, AppUser user) {
if (!address.getUser().getId().equals(user.getId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Not allowed to access/modify resource");
}
}
This method will check if the Address belongs to the user.
The address was gotten from a id in the path variable
The user was gotten from the id in the JWT
Update and delete endpoint call the checkResourceBelongsToUser method before doing any processing (updating or deleting). I'm comparing ids. Is my method enough to check if the user truly has access?
I am learning spring boot caching to apply this concept in our organization's project and I made a sample project called employe cache. I have four methods in my controller and service component insert, update, get, and getAll.For insert and get #Cacheable is working perfectly. Now I am calling getAllEmployee() first time then it is fetching data from the database. After that I am trying to update with #CachePut it updates the value in the database and again I am calling getAllEmployee() then it didn't return updated value from the cache. I also refer to the documentation for #CachePut. I also refer to some other documents like this and this but I didn't solve my problem. Also, When I am calling, no error is raised.
What I Tried is
These are my two APIs from EmplyeeController.java
#PostMapping(value = "/updateSalary")
private Boolean updateSalary(#RequestParam int salary, #RequestParam Integer id) {
return empService.updateSalary(salary, id);
}
#GetMapping(value = "/getAllEmployee")
private Object getAllEmployee() {
List<EmployeeMapping> empList = empService.getAllEmployee();
return !empList.isEmpty() ? empList : "Something went wrong";
}
These are my two methods from EmployeeService.java. I applied different keys to update the method but didn't work. My getAll() method has no parameter so I tried all the keys techniques for no parameter methods from here then also I didn't get any results.
#CachePut(key = "#root.method.name")
public Boolean updateSalary(int salary, int id) {
System.err.println("updateSalary method is calling in service");
if (empRepo.salary(salary, id) != 0) {
return true;
}
return false;
}
#Cacheable(key = "#root.method.name")
public List<EmployeeMapping> getAllEmployee() {
return empRepo.findAllEmployee();
}
These are my two methods from EmployeeRepository.java. I used #SqlResultSetMappings and #NamedNativeQueriesin EmployeeMetaModel.java with EmployeeMapping.java but there is no error in native query in EmployeeMetaModel.java because it's giving result from database.
#Transactional
#Modifying
#Query("update employee_cache e set e.salary = ?1 where e.id = ?2")
int salary(int salary, int id);
#Query(name = "EmployeeListQuery", nativeQuery = true)
List<EmployeeMapping> findAllEmployee();
Kindly help me to get rid of this I just need an updated value from the cache using getAllEmployee() after updateSalary() called.
There is an issue with how you've defined caching via annotations. Your #CachePut and #Cacheable don't use the same cache key. What you should actually have is something like this:
#CachePut(value = "employees", key = "T(org.springframework.cache.interceptor.SimpleKey).EMPTY")
public List<EmployeeMapping> updateSalary(int salary, int id) {
// update salary and return the list of employees
}
#Cacheable(value = "employees")
public List<EmployeeMapping> getAllEmployee() {
// return the list of employees
}
Here #CachePutand #Cacheable have the same cache key.d Now, when you call the updateSalary() method, #CachePut will replace the existing cached value for key "employees", with the result of the method i.e. list of employees with updated salary.
I have one data already saved in my databse based on my repository and service.i want to save another data with postman by changing only the player id.But it is not create a new entity data.it update the existing entity data.My question is how to update a data by my service when it finds a existing id.But when it finds a new id it will save a new data into databse.
This is my repo:
#Repository
#Transactional
public interface CricketPlayerRepository extends CrudRepository<CricketPlayer,String> {
Optional<CricketPlayer> findCricketPlayerByName(String name);
}
This is my service:
#Service
public class CricketPlayerService {
private CricketPlayerRepository cricketPlayerRepository;
public CricketPlayerService(CricketPlayerRepository cricketPlayerRepository) {
super();
this.cricketPlayerRepository = cricketPlayerRepository;
}
public CricketPlayerService() {
}
public Optional<CricketPlayer> getPlayerByName(String name){
return cricketPlayerRepository.findCricketPlayerByName(name);
}
public CricketPlayer save(CricketPlayer cricketPlayer){
Optional<CricketPlayer> id = cricketPlayerRepository.findById(cricketPlayer.getPlayerId());
if (id.isPresent()){
//code here
}
// if (entityManager.isNew(cricketPlayer)) {
// em.persist(cricketPlayer);
// return cricketPlayer;
// } else {
// return em.merge(cricketPlayer);
// }
return cricketPlayerRepository.save(cricketPlayer);
}
public Iterable<CricketPlayer> findAllPlayers() {
return cricketPlayerRepository.findAll();
}
public Optional<CricketPlayer> findPlayersById(String id) {
return cricketPlayerRepository.findById(id);
}
}
save and update operations in hibernate ( and other frameworks) are based on id value. if an id exists merge (update) entity and otherwise save new instance. So it cannot be done in this context.
1)If PlayerId is primary key id, then you would have called merge(entity). If PlayerId is present it will update else it will create new record.
2)If PlayrerId is not primary key id. Best practice is to avoid PlayerId as primary key.
In postman you should pass database table primary key id along with PlayerId.
Then you call merge(entity). It will take care of create or update based on primary key
id is null or not.
for example below if you have passed primary key id in request.
Entity e = new Entity();
if (entityFromRequest.getId() != null){ //this is the db id from request
//get the entity from db and then change the state
e = entity from db by using id
}
e.setPlayerId = entityFromRequest.getPlayerId
merge(e); // it will create or update record
I have the following test :
#Test
public void deleteUser(){
User user = new User("admin","admin");
service.createUser(user);
service.deleteUser(1);
assertTrue("Check that user is deleted: ", user.getId() < 1);
}
But it gives me AssertationError.
Why can I not do like that?
I create my user and then wanna test that I am able to delete the newly created user.
My delete method is just deleting from a hashmap the user.
Map<Long, User> users = new HashMap<Long, User>();
protected static long nextId = 0;
#Override
public long createUser(User user) {
user.setId(getNextId());
users.put(user.getId(), user);
return user.getId();
}
#Override
public void deleteUser(long id) {
users.remove(id);
}
Can somebody explain this to me?
Instead of accessing the User object, that you still have the reference to (independent of whether it's deleted), you should implement a method, that checks, whether a user is present in the class of your service variable:
public boolean containsUser(long userId) {
return users.containsKey(userId);
}
And then assert like so:
assertFalse("Check that user is deleted: ", service.containsUser(1L));
When you delete user from Map, you do nothing with user.id. That's why your assertion fails.
One way to change id when deleting
#Override
public void deleteUser(long id) {
User deletedUser = users.remove(id);
deletedUser.setId(-1);
}
Another (and better) way is to change test:
#Test
public void deleteUser(){
User user = new User("admin","admin");
long id = service.createUser(user);
service.deleteUser(id);
assertFalse("Check that user is deleted: ", service.hasUser(id));
}
Your test does not make any sense - you want to check if the user is deleted from the service, but instead you are checking the value of the Id property of the user object (which is null, or set to some value - you did not provide any code). As some users already suggested, you need to check if the user is actually contained within your service. Also, are you doing something inside your getNextId() method? If that is simply getter for your nextId variable, every single user you create will have Id set to 0 (but maybe you wanted it that way, who knows). Is there some code within getNextId that actually sets the value to something else?
I have been struggling with this issue for a while now, and can't seem to find a solution anywhere. Maybe I have misunderstood something, but would really appreciate it if someone could clear up things for me.
I am trying to create a OneToOne bidirectional relationsship between a User.class and a FacebookProfile.class.
That is I want to be able to look up the corresponding User entity from the FacebookProfile entity, and vice versa:
userInstance.getFbprofile();
fbprofileInstance.getUser();
My User.class:
#Entity
#Access(value=AccessType.FIELD)
public class User implements UserDetails {
#OneToOne(mappedBy="user")
private FacebookProfile fbprofile;
}
My FacebookProfile.class:
#Entity
#Access(value=AccessType.FIELD)
public class FacebookProfile {
#OneToOne (cascade=CascadeType.ALL)
#JoinColumn(name="USER")
private User user;
}
The new FacebookProfile and User instances are created in a Controller, and then sent through a Service layer to a DAO class which persists the objects.
I first create and persist a new User object.
I then create a new FacebookProfile and puts the newly created User in it (setUser). I then persist the FacebookProfile object.
The User ID is now stored in the FacebookProfile database table, but there is no reference from the User to the FacebookProfile so the following code returns a NullPointerException:
User tempUser = userService.findUserById(newUser.getId());
System.out.println("ID "+tempUser.getFbprofile().getId());
Below is the code from the Controller if something is unclear:
//Check if the Facebook user already exist
FacebookProfile fbprofile = facebookProfileService.findFacebookProfileById(fbId);
User newUser;
//Create a new FacebookProfile if it doesn't exist
if(fbprofile == null){
//Check if there is a user registered with the facebook email
newUser = userService.findUserByEmail(fbEmail);
// No User and No FacebookProfile exists
if(!newUser.isEnabled()){
newUser = new User();
newUser.setFirstname(fbFirstname);
newUser.setLastname(fbLastname);
//Set email
Email mail = new Email();
mail.setAddress(fbEmail);
mail.setName("Facebook");
newUser.addEmail(mail);
//Set gender
if(fbGender.equalsIgnoreCase("female")){
newUser.setGender(Gender.FEMALE);
}else if(fbGender.equalsIgnoreCase("male")) {
newUser.setGender(Gender.MALE);
}
userService.createUser(newUser);
}
FacebookProfile newProfile = new FacebookProfile();
newProfile.setId(Long.parseLong(fbId));
newProfile.setUsername(fbUsername);
newProfile.setFirstname(fbFirstname);
newProfile.setLastname(fbLastname);
newProfile.setName(fbName);
newProfile.setEmail(fbEmail);
if(!fbHometown.equals("")){
newProfile.setHometown(fbHometown);
newProfile.setHometownID(Long.parseLong(fbHometownID));
}
if(!fbLocation.equals("")){
newProfile.setLocation(fbLocation);
newProfile.setLocationID(Long.parseLong(fbLocationID));
}
newProfile.setLink(fbLink);
if(fbGender.equalsIgnoreCase("male")){
newProfile.setGender(Gender.MALE);
}else if (fbGender.equalsIgnoreCase("female")) {
newProfile.setGender(Gender.FEMALE);
}
newProfile.setUser(newUser);
this.facebookProfileService.createNewFacebookProfile(newProfile);
//newUser.setFbprofile(newProfile);
}else { //There already exists a FacebookProfile
newUser = fbprofile.getUser();
}
I feel like I have tried every possible solution to this and haven't got it to work.
I suspect that in one of my earlier attempts that the fbprofile reference was set in the User object, but never persisted because it was set after the User object was persisted. I am using JPA2 and EclipseLink.
If someone's got a solution to this it would be much appreciated.
Bi-Directional relations is not maintained by JPA. JPA designers had thought that maintaining bi-directional relations can cause deadlocks, inconsistencies... Toplink was supporting bi-directional relations before JPA.. I have used Toplink for many years, I did come accross some inconsistencies related to bi-directional relations.. You should maintain bi-directional relations manually.. Such as ;
newProfile.setUser(newUser);
newUser.setFbProfile(newProfile);
EDIT :
Well, you want me to elaborate my answer.. You should change your code that persist FbProfile entity such as ;
newProfile.setUser(newUser);
newUser.setFbprofile(newProfile);
this.facebookProfileService.createNewFacebookProfile(newProfile);
As an alternative , you could also change FbProfile setUser method ;
public void setUser(User aUser) {
if (this.user==aUser)
return;
if (this.user != null) {
this.user.setFbProfile(null);
}
this.user = aUser;
if (this.user!=null) {
this.user.setFbprofile(this);
}
}