Spring Data MongoRepository save causing Duplicate Key error - spring-boot

Here is the Entity:
#Document
#Data
public class ApplicationUser {
private String name;
#Indexed(unique = true)
private String email;
private String organization = null;
// other fields
}
I fetch this user using their email and then change their name. I use the autowired instance of ApplicationUserRepository.
ApplicationUser applicationUser = applicationUserRepository.findByEmail("abc#gmail.com");
applicationUser.setName("John Doe 2");
Then I try to update this entity again in the database:
applicationUserRepository.save(applicationUser);
I get a duplicate key error on the field email. Why is this happening?
As far as I get from the documentation, the save method updates the same document if the ObjectId is the same. Since I haven't changed the objectId then why is it trying to create a new ApplicationUser during saving?

I got the solution.
When creating the entity, I have to explicitly declare the Id.
Here is the Entity:
#Document
#Data
public class ApplicationUser {
#Id
private ObjectId _id;
private String name;
#Indexed(unique = true)
private String email;
private String organization = null;
// other fields
}

I had similar issue where I was retrieving by id and then trying to update the retrieved POJO and then save it back with MongoRepository.save() call. It was on MongoDB 4.x with Spring Boot 2.1.0. I added the #Transactional annotation to my service method and everything worked like a charm. The duplicate key exception on id field was resolved.

Related

I have a field in database which I do not want to map in my spring java model while making a get call

I have a database table in which there is a field which I do not want to map to my model class while making a get call. Is there any annotation to handle this use case?
When persisting Java objects into database records using an Object-Relational Mapping (ORM) framework, we can ignore fields by adding the #Transient annotation to those fields.
#Entity
#Table(name = "Users")
public class User {
#Id
private Integer id;
private String email;
private String password;
#Transient
private Date loginTime;
// getters and setters
}

Find the updated fields on update request

I have a user entity as
#Entity
public class User {
#Id
private Long id;
private String name;
private String address;
// getter / setter
}
And controller method like:
#PutMapping(value = "/user")
public ResponseEntity<?> updateUser(#RequestBody User user) {
userRepository.save(user);
// ...
}
Now What I am trying to do is finding the field that is being updated.
Example:
If the only name is present I need some message like "Updated field is name".
Is there any better way other than comparing the fields one by one with the database stored values.
you need getUser method. for example: userRepository.getUser(user.id)
then you return the result

Redis #Reference does not work in Spring Data Redis

I am facing issues while implemeting #Reference in Spring Boot + Spring Data Redis. Address is a List in Employee and when I saved the office and home address and I was expecting the data to be saved with the Employee. But data did not get saved and hence unable to search the Address using street.
Employee.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("employees")
public class Employee {
#Id #Indexed
private String id;
private String firstName;
private String lastName;
#Reference
private List<Address> addresses;
}
Address.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("address")
public class Address {
#Id
private String id;
#Indexed
private String street;
private String city;
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeAdressTest extends RepositoryTestSupport{
#Autowired private EmployeeRepository employeeRepository;
#Before
public void setUp() throws JsonProcessingException {
Address home = Address.builder().street("ABC Street").city("Pune").build();
Address offc = Address.builder().street("XYZ Street").city("Pune").build();
Employee employee1 = Employee.builder().firstName("Raj").lastName("Kumar").addresses(Arrays.asList(home, offc)).build();
employeeRepository.save(employee1);
List<Employee> employees = employeeRepository.findByAddresses_Street("XYZ Street");
System.out.println("EMPLOYEE = "+employees);
}
#Test
public void test() {
}
}
Spring Doc:
8.8. Persisting References
Marking properties with #Reference allows storing a simple key reference instead of copying values into the hash itself. On loading from Redis, references are resolved automatically and mapped back into the object, as shown in the following example:
Example 30. Sample Property Reference
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
mother = people:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56
Reference stores the whole key (keyspace:id) of the referenced object.
?
Spring Data Redis requires you to save the objects stored in home and office separately from the referencing object employee1.
This is (now) stated in the official documentation at the very end of chapter 8.8: https://docs.spring.io/spring-data-redis/docs/current/reference/html/#redis.repositories.references
So if you save home and office to the database before saving employee1 you should be fine.
The same btw holds valid for updates you make to referenced objects later on. Just saving the referencing object alone does not save the updates on the referenced objects.

Updating object with null field in Spring

I'm working with Spring App, so to work with DB I use Spring Data JPA. Firstly I saved an object. And after some time I need to update this object in the table. But at this moment my object contains one field which is null. But I don't want to update this field with null. So my question is how to prevent updating fields with null? Maybe there is an annotation or some property to solve my problem.My entity:
#Entity
#Table(name = "users")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long id;
#NotNull
#Column(name = "user_name")
#Field
private String username;
#NotNull
#Column(name = "user_identity")
private String identity;
#Column(name="user_image")
private String image;
#Column(name="user_joined")
private String date;
#Column(name="user_origin")
private String origin;
#Column(name="user_sub")
private String sub;
I save and update this entity with implementation of JpaRepository:
#Repository
public interface UserRepository extends JpaRepository<User, Long>
it looks like this:
#Autowired
private UserRepository userRepository;
....
userRepository.save(user);
I've saved my object with not null sub-field. And now I want to update some fields of saved entity, but not sub field, which is null in current object. I wonder if there is any possibility to avoid changing user_sub field to null?
You can add #DynamicUpdate annotation to your User class. This will ignore the fields whose values are null. You can simply do like:
//other annotations
#DynamicUpdate
public class User {
// other codes inside class
}
You can follow a good example from Mkyong's site.
Thanks, guys. I found the solution: #Query will help to update fields that I need

JPQL Special Query

I have two entity bean :
#Entity
public class User {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<Comment>();
//SOME OTHER CLASS VARIABLES
//GETTERS AND SETTERS
}
and my Comment class is like this :
#Entity
public class Comment {
#Id
#GeneratedValue
private Long id;
private String title;
private String content;
#ManyToOne
private User user
//SOME OTHER CLASS VARIABLES
//GETTERS AND SETTERS
}
now I know that I can get the User Object from session and set the user for my comment like this in order to be able to use the join feature in JPA:
commentObject.setUser(TheSessionGrabedUserObject/UserObjectWhichHasFetchedFromDbUsingUserId);
but as long as I have the userId for my user Object I do not need to do this.
I'm looking for a way to insert this foreignKey into my comment table without getting the User Object from session or maybe query to database to fetch it first !
how I'm gonna do it using JPQL ?
You can use the entityManager.getReference() method. In your case:
entityManager.getReference(User.class, userId);
This will not perform any DB query, but will give you a User instance with only the ID populated, and you can pass that to commentObject.setUser().

Resources