Spring Data Rest - Нарушение первичного ключа во время PUT или PATCH - PullRequest
0 голосов
/ 28 октября 2018

У меня проблема при PUTPING или PATCHing объекта Profile через Spring Data Rest.Ошибка возникает, когда я PUT или PATCH те же или новые данные для свойства «skill» или «jobs».

Вот что возвращает curl:

{"cause":{"cause":{"cause":null,"message":"Unique index or primary key violation: \"PRIMARY_KEY_6E ON PUBLIC.TRAINER_PROFILE_JOBS(TRAINER_PROFILE_ID, JOBS_ID) VALUES (77, 79, 2)\"; SQL statement:\ninsert into trainer_profile_jobs (trainer_profile_id, jobs_id) values (?, ?) [23505-197]"},"message":"could not execute statement"},"message":"could not execute statement; SQL [n/a]; constraint [\"PRIMARY_KEY_6E ON PUBLIC.TRAINER_PROFILE_JOBS(TRAINER_PROFILE_ID, JOBS_ID) VALUES (77, 79, 2)\"; SQL statement:\ninsert into trainer_profile_jobs (trainer_profile_id, jobs_id) values (?, ?) [23505-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"}

Приложение создаетследующий вывод:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY_KEY_6E ON PUBLIC.TRAINER_PROFILE_JOBS(TRAINER_PROFILE_ID, JOBS_ID) VALUES (77, 79, 2)"; SQL statement:
insert into trainer_profile_jobs (trainer_profile_id, jobs_id) values (?, ?) ...
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_6E ON PUBLIC.TRAINER_PROFILE_JOBS(TRAINER_PROFILE_ID, JOBS_ID) VALUES (77, 79, 2)"; SQL statement:
insert into trainer_profile_jobs (trainer_profile_id, jobs_id) values (?, ?) [23505-197]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:357) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:101) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.mvstore.db.MVSecondaryIndex.requireUnique(MVSecondaryIndex.java:236) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.mvstore.db.MVSecondaryIndex.add(MVSecondaryIndex.java:202) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.mvstore.db.MVTable.addRow(MVTable.java:732) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.command.dml.Insert.insertRows(Insert.java:182) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.command.dml.Insert.update(Insert.java:134) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.command.CommandContainer.update(CommandContainer.java:102) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.command.Command.executeUpdate(Command.java:261) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:199) ~[h2-1.4.197.jar:1.4.197]
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:153) ~[h2-1.4.197.jar:1.4.197]
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-2.7.9.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-2.7.9.jar:na]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
    ... 149 common frames omitted

В настоящее время есть только один способ заставить его работать: 1. PUT или PATCH с пустым массивом для «заданий» и «навыков» 2. Затем снова PUT или PATCH с новыми данными

Вот как выглядит сущность, прежде чем я пытаюсь PUT или PATCH данные:

curl -s -XGET -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" http://localhost:2222/trainerProfiles/66
{
  ...
  "jobs" : [ {
    "period" : {
      "start" : "2015-01-02",
      "end" : "2017-01-25"
    },
    "company" : "Lorem ipsum dolor sit amet",
    "sector" : "Lorem ipsum dolor sit amet",
    "position" : "Lorem ipsum dolor sit amet",
    "description" : "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat."
  } ],
  "skills" : [ {
    "topic" : "java",
    "level" : "EXPERT"
  }, {
    "topic" : "spring",
    "level" : "EXPERT"
  } ],
  "_links" : {
    ...
  }
}%

Как видите, свойства навыков и заданий встроены в сущность профиля с тех пор, как я это сделал.не создавать экспортированный репозиторий JPA для них.Это предназначено.

Чтобы дать вам полную картину моих сущностей, мне нужно представить некоторые базовые классы, унаследованные от:

public interface BaseEntity {
    public Long getId();    
    public void setId(Long id); 
}

@Data
@MappedSuperclass
public class AbstractBaseEntity implements BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}

@Data
@EqualsAndHashCode(callSuper=true)
@MappedSuperclass
public abstract class AbstractOwnedEntity extends AbstractBaseEntity implements OwnedEntity {
    @NotNull
    @ManyToOne
    private Company owner;  
}

Это сущность, предоставляемая через Spring Data Restчто вызывает у меня головную боль:

@NoArgsConstructor
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
public class Profile extends AbstractOwnedEntity {
    ...

    @NotNull
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<JobEntry> jobs = new HashSet<JobEntry>();

    @NotNull
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<SkillEntry> skills = new HashSet<SkillEntry>();

    public Profile(...) {
        ...
    }

    public void addJob(JobEntry job) {
        this.jobs.add(job);
    }

    public void addSkill(SkillEntry skill) {
        this.skills.add(skill);
    }
    ...
}

Репозиторий JPE - это очень базовый репозиторий CrudRepository с некоторыми SPEL в форме @PreAuthorize, @PostFilter и т. д. для реализации управления доступом (здесь опущено)

@RepositoryRestResource
public interface TrainerProfileRepository extends CrudRepository<TrainerProfile, Long> {
    ...
}

1 Ответ

0 голосов
/ 30 октября 2018

Если я правильно помню, я думаю, что вам нужно предоставить идентификаторы для сущностей, которые не были открыты через репозитории отдыха - в вашем случае, Skills and Jobs: в противном случае, как фреймворк узнает, что ваши запросы PUT / PATCHссылается на существующую сущность или нет.

Вы можете выставить идентификаторы для этих 2 классов в конфигурации, как указано здесь:

Как предоставить идентификатор ресурса с помощью Spring Data Rest

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...