Spring Data calling Update instead of Insert when saving with custom primary key
Problem:
You have a class named User
with fields like id
, email
, role
, etc. You also have a UserRepository
for database operations. When you try to save a new User
object with a pre-set id
, Spring thinks it's an existing record and tries to update it. But since the record doesn't exist, you get an error TransientDataAccessResourceException.
// A Model class with Custom ID
@Table("users")
public class User {
@Id
String id;
String email;
String role;
}
public interface UserRepository extends ReactiveCrudRepository<User,String> {
}
// Create an User
User user = User.builder()
.id(firebaseUserDetails.getUid())
.email(firebaseUserDetails.getEmail())
.phone(firebaseUserDetails.getPhoneNumber())
.build();
userRepository.save(user);
// throws error
org.springframework.dao.TransientDataAccessResourceException:
Failed to update table [users]; Row with Id [BkYsodTm1kWN8jID36KqnfGLmVJc]
does not exists
Why this happens:
Spring Data behaves this way because if you set the id
field, it assumes that you're working with an existing record, so it tries to update it instead of inserting a new one.
Solution:
You can let Spring know that the record is new and should be inserted, not updated. For this:
- Make your
User
class implement thePersistable
interface. - Add a
boolean
field, maybe call itisNewEntry
, to indicate whether the record is new or existing. - Implement the
isNew
method to return the value ofisNewEntry
.
@Builder
@Table("users")
public class User implements Persistable<String> {
@Id
String id;
String email;
String role;
String phone;
Long credits;
// This new field tells us if the record is new
@Transient
@Builder.Default
private boolean isNewEntry = true;
// This method checks if the record is new
public boolean isNew() {
return isNewEntry;
}
}
Now, when you save a user object with isNewEntry
set to true
, Spring will insert it as a new record instead of trying to update it.