У меня проблема при 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> {
...
}