Yasin Eraslan
Yasin Eraslan

Reputation: 191

Spring does Update instead of save

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

Answers (6)

AndrewS
AndrewS

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

Hantsy
Hantsy

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

fyrkov
fyrkov

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

Yasser Kantour
Yasser Kantour

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

suseelkumar annamraju
suseelkumar annamraju

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

BlackPearl
BlackPearl

Reputation: 300

It seems like you forgot to use annotation @Entity for your entity class User

Upvotes: -4

Related Questions