skip to Main Content

I have this Entity class with nickname String as a key.


@Data
@Entity
@Table(name="players")
public class Player {
  @Id
  private String nickname;
  @Column(name="name")
  private String name;
  @Column(name="surname")
  private String surname;
...
...
...
}

Controller

  @PostMapping(value="/addPlayer", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces ={MediaType.APPLICATION_JSON_VALUE})
  public ResponseEntity<Player> save(@RequestBody Player player) throws Exception {
      return new ResponseEntity<>(playerService.save(player), HttpStatus.OK);
  }

Service (interface)

 Player save(Player player) throws Exception;

Service Impl

  @Override
  public Player save(Player player)throws Exception{
    if(player.getName() != null && (!player.getName().isEmpty() && (!player.getName().isBlank())) && 
         (player.getSurname() != null && (!player.getSurname().isEmpty() && (!player.getSurname().isBlank()))) &&
         (player.getNickname() != null && (!player.getNickname().isEmpty() && (!player.getNickname().isBlank())))) {
    return playerRepository.save(player);
  }
    throw new IllegalArgumentException("provide name,surname and nickname");
  }

Repository

@Repository
public interface PlayerRepository extends JpaRepository<Player, String> {
//somestuff
}

I have this situation in DB.

db

If I try this request :

postman request

then in DB i have this bad behavior

db result

Data are overwrite on key " nickname5 "
work like a patch 🙁 , I don’t understand how and why.

I try to add unique annotation at nickname column but not work …


  @Id
  @Column(unique = true)
  private String nickname;

Can I ask why i have this behavior and how I can fix it ?

(yes I can do manually with some check in a service but I think I miss some annotation or functionality about data-jpa-framework)

Other than this bug, if you see things that are not right or things that can be done better in the code, I welcome suggestions. I am here to improve .
Thank you !


@Edit

I have add the unique constraint on ‘nickname’ pkuk
But behavior is the same. Name and Username are update if I pass a Nickname(primary-key) already in the database

2

Answers


  1. You are using a nickname as a primary key in your table. While you’ve annotated it with @Id JPA makes it a primary key and it is unique.

    As for your save() method, here it checks whether the object is present or not in DB if yes then update or else create.

    In your application.yml add

    spring:
      jpa:
        show-sql: true
    

    then you can see the SQL query run by JPA to know how it actually works

    Login or Signup to reply.
  2. As we discussed into comments this is my answer and some explanation about your case:

    First of all you have to avoid using String as primary key because in this case because when you are going to add new use with return playerRepository.save(player); and a row with the same value as primary key is already persisted to database it will do update instead to throw exception, because save() method from JpaRepository work so.

    JPA follows the latter approach. save() in Spring Data JPA is
    backed by merge() in plain JPA, therefore it makes your entity managed
    as described above. It means that calling save() on an object with
    predefined id will update the corresponding database record rather
    than insert a new one, and also explains why save() is not called
    create().

    In your case you should have something like this one approach:

    Entity:

    @Data
    @Entity
    @Table(name="players")
    public class Player {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
    
      @Column(name = "nickname", unique = true)
      private String nickname;
    
      @Column(name="name")
      private String name;
    
      @Column(name="surname")
      private String surname;
    
    }
    

    Database Table:

    CREATE TABLE IF NOT EXISTS players
    (
        id       bigserial
            primary key,
        name     varchar(255),
        nickname varchar(255)
            unique,
        surname  varchar(255)
    );
    

    And when you will try to persist a value that already exist in database with the same nickname:

    You will have the next one exception:

    ERROR: duplicate key value violates unique constraint "players_nickname_key" Detail: Key (nickname)=(nickname) already exists.
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search