How to prevent NULL entry in UPDATE operation using CRUD Repository? - spring

Consider the following Events:-
CREATE User [id=1, name=Ram, city=Delhi, email=abc#gmail.com, phone=12345]
UPDATE User [id=1, city=Mumbai, phone=56789]
For CREATE operation, this is what is stored in the database:-
[id=1, name=Ram, city=Delhi, email=abc#gmail.com, phone=12345]
However, when I perform the UPDATE operation, fields which are not updated becomes null
[id=1, name=null, city=Mumbai, email=null, phone=56789]
Now, my question is that how do I prevent name and email from becoming NULL ??
Here is the code snippet :-
Entity Class:-
#Entity
public class User {
#Id
private Integer id;
private String name;
private String city;
private String email;
private String phone;
//Setters and Getters
}
Repository:-
import org.springframework.data.repository.CrudRepository;
import com.therealdanvega.domain.User;
public interface UserRepository extends CrudRepository<User, Integer>{
}
Application Class :-
#SpringBootApplication
public class JsontodbApplication implements CommandLineRunner {
#Autowired
private UserRepository userRepo;
public static void main(String[] args) {
SpringApplication.run(JsontodbApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
/* CREATE USER */
userRepo.save(createUser());
/* UPDATE USER */
userRepo.save(updateUser());
System.out.println(userRepo.findOne(1));
}
public User createUser() {
User user = new User();
user.setId(1);
user.setName("Ram");
user.setCity("Delhi");
user.setEmail("abc#gmail.com");
user.setPhone("12345");
return user;
}
public User updateUser() {
User user = new User();
user.setId(1);
user.setCity("Mumbai");
user.setPhone("56789");
return user;
}
}

Your code doesn't work like you think it does. For Spring it is actually something like that :
Take new object User with id = 1 , name = Ram ... and put it into that base.
Take new object User with id = 1 , city = Mumbai ... and put it into that base.
Spring Repository works like that, if you save object with NULL id, it will add it. If you save object with given id it will update EVERY value that has changed. So for spring you actually update every field, some for new value and most of them for NULLs. MORE INFO
You should get your object which is return by first save function, and update it again. Like that :
#SpringBootApplication
public class JsontodbApplication implements CommandLineRunner {
#Autowired
private UserRepository userRepo;
public static void main(String[] args) {
SpringApplication.run(JsontodbApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
/* CREATE USER */
User user = userRepo.save(createUser(new User()));
/* UPDATE USER */
userRepo.save(updateUser(user));
System.out.println(userRepo.findOne(1));
}
public User createUser(User user) {
user.setName("Ram");
user.setCity("Delhi");
user.setEmail("abc#gmail.com");
user.setPhone("12345");
return user;
}
public User updateUser(User user) {
user.setCity("Mumbai");
user.setPhone("56789");
return user;
}
}

Related

How to handle objects created within the method under test

I have the following model classes:
#Data
public class Address {
private String street;
private int number;
}
#Data
public class Person {
private String name;
private Address address;
}
and the following services:
#Service
public class MyService {
private final OtherService otherService;
public MyService(OtherService otherService) {
this.otherService = otherService;
}
public void create() {
Person myPerson = new Person();
myPerson.setName("John");
otherService.synchronize(myPerson);
myPerson.getAddress().setNumber(12);
}
}
#Service
public class OtherService {
public void synchronize(Person person) {
Address address = new Address();
address.setStreet("sample street");
address.setNumber(123);
person.setAddress(address);
}
}
I want to write a unit test for MyService. This is the not working version of the test:
#ExtendWith(SpringExtension.class)
class MyServiceTest {
#Mock OtherService otherService;
#InjectMocks MyService myService;
#Test
void test_create() {
// GIVEN
doNothing().when(otherService).synchronize(any(Person.class));
// WHEN
myService.create();
// THEN
verify(otherService).synchronize(any());
}
}
This fails because the myPerson object is created within the method being tested and therefore I get a NullPointerException when running the test. How could I deal with this issue? should I capture the value passed to the otherService?
There's a little complexity but it's not bad. Replace your doNothing call with something like this:
Mockito.doAnswer(
new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Exception {
Person arg = invocation.getArgument(0);
arg.setAddress(new Address());
return;
}
}).when(otherService).synchronize(any(Person.class));

What is the CLI command to view inside of a set data type in redis

I user a CRUDRepository in my spring data redis project to persist a redis hash in my redis cluster. i have rest api written to persist and get thte values of the data. this works fine.
however my entity annotated with RedisHash is being saved as a set / and i am not able to look inside the value using redis cli.
how do i look inside a set data type(without popping) in redis cli
i looked at redis commands page https://redis.io/commands#set
i only get operations which can pop value . i neeed to simply peek
EDIT:
to make things clearer, i am using spring crudrepo to save the user entity into redis data store. the user entity gets saved as a set data type.
when i query back the user details, i can see entire details of the user
{
userName: "somak",
userSurName: "dattta",
age: 23,
zipCode: "ah56h"
}
i essentially want to do the same using redis cli... but all i get is
127.0.0.1:6379> smembers user
1) "somak"
how do i look inside the somak object.
#RestController
#RequestMapping("/immem/core/user")
public class UserController {
#Autowired
private UserRepository userRepository;
#RequestMapping(path = "/save", method = RequestMethod.GET, produces = "application/json")
#ResponseStatus(HttpStatus.OK)
public void saveUserDetails() {
User user = new User();
user.setAge(23);
user.setUserName("somak");
user.setUserSurName("dattta");
user.setZipCode("ah56h");
userRepository.save(user);
}
#RequestMapping(path="/get/{username}", method = RequestMethod.GET, produces = "application/json")
public User getUserDetails(#PathVariable("username") String userName) {
return userRepository.findById(userName).get();
}
}
#Repository
public interface UserRepository extends CrudRepository<User, String>{
}
#RedisHash("user")
public class User {
private #Id String userName;
private #Indexed String userSurName;
private #Indexed int age;
private String zipCode;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserSurName() {
return userSurName;
}
public void setUserSurName(String userSurName) {
this.userSurName = userSurName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
}
I don't understant your descr with your problem, but I understand your title.
In redis set, the member is always string type.
I hope you can offer more info about UserRepository.save:
User user = new User();
user.setAge(23);
user.setUserName("somak");
user.setUserSurName("dattta");
user.setZipCode("ah56h");
userRepository.save(user);
And you can check your redis data and check data type when rest api invoked.

Spring boot H2 database application

I have created a sample project with following code. Even if i am not providing table create statement in the data.sql, it is creating the table. how to stop that. Sample code is present below
Can you please let me know what I am doing wrong? I have removed the import statements below as the post was not allowing to put so much code here.
package com.example.demo;
// Model class
#Entity
#Table(name="reservation")
public class Reservation {
#Id
private Long id;
#Column(name="user_id")
private Long userId;
#Column(name="party_size")
private int partySize;
#Column(name="restaurant_id")
private Long restaurantId;
#Column(name="date")
private LocalDateTime dt;
public Reservation() {}
public Reservation(Long id, Long userId, int partySize) {
this.id = id;
this.userId = userId;
this.partySize = partySize;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public int getPartySize() {
return partySize;
}
public void setPartySize(int partySize) {
this.partySize = partySize;
}
public Long getRestaurantId() {
return restaurantId;
}
public void setRestaurantId(Long restaurantId) {
this.restaurantId = restaurantId;
}
public LocalDateTime getDt() {
return dt;
}
public void setDt(LocalDateTime dt) {
this.dt = dt;
}
}
package com.example.demo;
#SpringBootApplication
public class ReservationApp {
public static void main(String[] args) {
SpringApplication.run(ReservationApp.class, args);
}
}
package com.example.demo;
#RestController
#RequestMapping("/v1")
public class ReservationController {
#Autowired
private ReservationService reservationService;
// ------------ Retrieve all reservations ------------
#RequestMapping(value = "/reservations", method = RequestMethod.GET)
public List getAllReservations() {
return reservationService.getAllReservations();
}
package com.example.demo;
import org.springframework.data.repository.CrudRepository;
public interface ReservationRepository extends CrudRepository<Reservation,String> {
}
package com.example.demo;
#Service
public class ReservationService {
#Autowired
private ReservationRepository reservationRepository;
// Retrieve all rows from table and populate list with objects
public List getAllReservations() {
List reservations = new ArrayList<>();
reservationRepository.findAll().forEach(reservations::add);
return reservations;
}
}
try to remove the spring boot hibernate configuration
spring.jpa.hibernate.ddl-auto = update
Which is able of creating/updating the database schema from entities
To disable automatic DDL generation, set the following property to false in application.properties:
spring.jpa.generate-ddl = false
For more information and fine-grained control, please see the documentation.
Set the ddl generation to none in the application.properties:
spring.jpa.hibernate.ddl-auto=none

How to add an object to existing List using Spring Mongo db?

this is class A
#Document
class User{
private String id ;
private String name;
#Dbref
private List<Socity> Socitys;
}
and this is class Socity
#Document
class Socity{
private String id ;
private String name;
}
and this is the add user function
public User addUser(User user) {
List<Socity> socity = new ArrayList<>();
user.setsocitys (socity );
return userRepository.save(user);
}
I want to add a socity to an existing user
i try this but it doesn't work
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run (App.class, args);
SocityDao SDao = ctx.getBean(SocityDao .class);
UserRepository userRepository = ctx.getBean(UserRepository.class);
User u = userRepository.findOne("");
Socity s = new Socity("soc1");
SDao .addSocity(e);
u.getSocitys().add(e);
}
this is the rest service
#RequestMapping(value = "up/{id}", method = RequestMethod.POST ,produces =
"application/json")
public User addSocityToUser(#RequestBody Socity, #PathVariable String id)
{
return SocityDAO.addSocityToUser(e, id);
}
In the end of your code add userRepository.save(u) to persist your changes to the DB.
As long as it as an ID (because it is a persisted object) it will be updated. if it has no ID it will be saved as a new object in the DB.
Looks like you forget to save user, after you add new socity. Please check my updates
#Document
public class Socity {
private String id ;
private String name;
}
#Document
public class User {
private String id;
private String name;
#DBRef
private List<Socity> socitys = new ArrayList<>();
}
Then you don't need to use your addUser() method. When you want to add new user just use
userRepository.save(user);
You also need two repositories
public interface SocityRepository extends MongoRepository<Socity, String> {
}
and
public interface UserRepository extends MongoRepository<User, String> {
}
And what you need in the main method
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run (App.class, args);
UserRepository userRepository = ctx.getBean(UserRepository.class);
SocityRepository socityRepository = ctx.getBean(SocityRepository.class);
User u = userRepository.findOne("");
Socity s = socityRepository.save(new Socity("soc1"));
u.getSocitys().add(s);
userRepository.save(u);
}
It is always better to Use the MongoTemplate to write an update Query and use Push function to add to a list.
#Autowired
private MongoTemplate mongoTemplate;
function(String id, Socity socity){
Query query = new Query(Criteria.where("id").is(id));
Update update = new Update();
update.push("Socitys", socity);
mongoTemplate.updateFirst(query, update, User.class);
}

Update database ManytoOne relationship (Spring Boot + MVC +Thymeleaf)

I have two entity class.one is PhaseEntity and another is TaskEntity. PhaseId will be the foreign key of TaskEntity class. I can create and save the value to the database but cannot update the database.
Portion of TaskEntity class:
#ManyToOne(optional=false)
#JoinColumn(name="phaseId")
private PhaseEntity phaseEntity;
Controller class:
public class TaskController {
#Autowired
private TaskService taskService;
#Autowired
private PhaseService phaseService;
#RequestMapping(value="/task/create",method=RequestMethod.GET)
public String createForm(Model model,Principal principal){
model.addAttribute(new TaskEntity());
model.addAttribute("body", "task/task-create");
model.addAttribute("generaltaskDto",new GeneralTaskDto());
model.addAttribute("phaseEntities", phaseService.phaseList());
return "layouts/default";
}
#RequestMapping(value="/task/create",method=RequestMethod.POST)
public String createFormPost(Model model,GeneralTaskDto generaltaskDto,BindingResult result){
TaskEntity taskAndPhase=generaltaskDto.getTaskEntity();
taskAndPhase.setPhaseEntity(phaseService.getPhaseByPhaseId(generaltaskDto.getPhaseId()));
taskService.saveTask(taskAndPhase);
return "redirect:/task/list";
}
#GetMapping(value="/task/update/{id}")
public String updateTask(Model model,#PathVariable String id){
TaskEntity taskEntity= taskService.getTaskId(Integer.parseInt(id));
model.addAttribute("body", "task/task-create");
model.addAttribute("phaseEntities", phaseService.phaseList());
return "layouts/default";
}
GeneraltaskDto class:
public class GeneralTaskDto {
private TaskEntity taskEntity=new TaskEntity();
private Integer phaseId;
public TaskEntity getTaskEntity() {
return taskEntity;
}
public void setTaskEntity(TaskEntity taskEntity) {
this.taskEntity = taskEntity;
}
public Integer getPhaseId() {
return phaseId;
}
public void setPhaseId(Integer phaseId) {
this.phaseId = phaseId;
}
}
here is the client page of the application
can anyone help plz how to update the database with controller request. Thanks in advance.
Please try adding these lines in your controller under updateTask method after TaskEntity taskEntity= taskService.getTaskId(Integer.parseInt(id)); line.
PhaseEntity phaseEntity=taskEntity.getPhaseEntity();
generaltaskDto.setTaskEntity(taskEntity);
generaltaskDto.setPhaseId(phaseEntity.getPhaseId());
model.addAttribute("generaltaskDto", generaltaskDto);

Resources