Reputation: 191
I am trying to code a little reactive backend with R2DBC and run into a thing I do not really understand. I dont know why but Spring is trying to update an entry instead of saving it to the database.
My User Model:
@Table("user")
@NoArgsConstructor
@Data
public class User {
@Id
private String id;
private String username;
private String password;
public User(String id,String username,String password){
this.id = id;
this.username = username;
this.password=password;
}
My Controller:
@RestController
public class UserController {
` private final UserRepository userRepository`;
@Autowired
public UserController(UserRepository userRepository){
this.userRepository = userRepository;
}
@PostMapping("/create")
public Mono<User> createUser(@RequestBody User user){
return userRepository.save(user);
}
When I sent a POST request to this endpoint with input like this for example:
{ "id" : "re", "username" : "ehmmidk", "password" : "dsadsadsadsa" }
it does an update insted of a save even when there is no entries in my database.
My schema looks like this:
CREATE TABLE user (
id VARCHAR(255) NOT NULL ,
username VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE(username)
);
Upvotes: 5
Views: 8595
Reputation: 543
The answer by fyrkov is correct: https://stackoverflow.com/a/64170679/928550
I have however discovered that using Optimistic locking is another way of getting Spring Data R2DBC to do the right thing when you are not using database generated id values.
eg. Add a @Version annotated fields to you JPA entities.
@Version private Long version;
I'm not exactly sure why, but for it worked.
Upvotes: 2
Reputation: 9241
Check my new example for upcoming Spring Boot 2.4, Spring 5.3, and Spring Data R2DBC 1.2.
I am using Postgres in this example. It used ApplicationRunner to initialize some sample data into the database.
You set the identifier a non-null value when saving the User
entity(not a Persistable
), Spring Data R2DBC uses it to check if the entity is new. If the entity is a Persistable
, it will use the isNew
method to determine if the entity is new.
However, you can insert data manually using R2dbc DatabaseClient
to execute SQL queries as expected, check my DatabaseClient example here(but I used a database generated id here).
Upvotes: 1
Reputation: 2715
The reason could be that you are posting an entity with the pre-filled id
:
{ "id" : "re", "username" : "ehmmidk", "password" : "dsadsadsadsa" }
What I spotted is that if a declared entity is implementing Persistable
interface it must implement isNew()
method which defines the behavior of repository.save()
- will it fire an INSERT
or an UPDATE
.
I see that in your case you do not implement Persistable
but maybe then the default behavior is
boolean isNew() { return id == null; }
That might mean in your case that the entity is considered as not new by Spring data r2dbc and that's why it makes an UPDATE
.
However this is only my guess.
Upvotes: 9
Reputation: 24
You need to ad the @GeneratedValue(strategy = GenerationType.IDENTITY)
. Spring's Crud repositories do not have create and update methods but only save (see also saveAndFlush
). It handles creation and update through @id
, so if the id
field is present it performs an update
Upvotes: 1
Reputation: 33
@Entity & @GeneratedValue should be added to your pojo.
@GeneratedValue will help to define the strategy(like Identify/Sequence) for primary key value generation.
If possible provide your update sql query printed in console for further analysis.
Upvotes: -4
Reputation: 300
It seems like you forgot to use annotation @Entity
for your entity class User
Upvotes: -4