#java #spring #postgresql #hibernate #one-to-many
#java #весна #postgresql #спящий режим #один ко многим
Вопрос:
Я получаю эту ошибку, когда пытаюсь обновить два объекта с помощью отношения один ко многим.
Это первый класс сущности:
package com.example.demo.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SelectBeforeUpdate;
@Entity
@Table(name = "tags", schema = "public")
@NoArgsConstructor
@SelectBeforeUpdate
@Data
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Long id;
@Column(name = "tag")
private String tag;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
public Tag(String tag, Product product) {
this.tag = tag;
this.product = product;
}
}
Это второй класс объектов:
package com.example.demo.entity;
import com.example.demo.dto.ProductDto;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@Entity
@NoArgsConstructor
@Table(name = "products", schema = "public")
@Data
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "name")
private String name;
@Column(name = "price")
private double price;
@Column(name = "added")
private Date added;
@OneToMany(mappedBy = "product", cascade = CascadeType.MERGE, orphanRemoval = true)
@Fetch(value = FetchMode.SELECT)
private List<Tag> tags;
public Product(final ProductDto productDto) {
this.id = productDto.getId();
this.name = productDto.getName();
this.price = productDto.getPrice();
this.added = new Date(productDto.getAdded());
this.tags = convertTagDtoToTag(productDto.getTags());
}
public List<Tag> convertTagDtoToTag(final List<String> tagDtos) {
return tagDtos
.stream()
.map(t -> new Tag(t, this))
.collect(Collectors.toList());
}
}
Этот метод, в котором я пытаюсь обновить:
public Product updateProduct(final ProductDto productDto) {
final Product product = this.productRepository.findById(productDto.getId()).map(p -> {
p.setName(productDto.getName());
p.setPrice(productDto.getPrice());
p.setAdded(new Date(productDto.getAdded()));
p.getTags().clear();
p.getTags().addAll(p.convertTagDtoToTag(productDto.getTags()));
return p;
}).orElse(null);
return this.productRepository.save(product);
}
И я получаю эту ошибку:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "tags_pkey"
Detail: Key (id)=(1) already exists.
Я пишу этот метод, но я думаю, что есть лучший способ.
public Product updateProduct(final ProductDto productDto) {
final Product product = this.productRepository.findById(productDto.getId()).map(p -> {
p.setName(productDto.getName());
p.setPrice(productDto.getPrice());
p.setAdded(new Date(productDto.getAdded()));
updateTag(p.getTags(), p.convertTagDtoToTag(productDto.getTags()));
return p;
}).orElse(null);
return this.productRepository.save(product);
}
private void updateTag(List<Tag> serverTags, List<Tag> frontedTags) {
for (int i = 0; i < serverTags.size(); i ) {
serverTags.get(i).setTag(frontedTags.get(i).getTag());
}
}
Также у меня есть файл data.sql
INSERT INTO products (id, name, price, added) values (1, 'First product', 100, '2000-09-01');
INSERT INTO products (id, name, price, added)
values (2, 'Second product', 200, '2010-10-11');
INSERT INTO products (id, name, price, added)
values (3, 'Third product', 300, '2010-11-04');
INSERT INTO tags (id, tag, product_id)
values (1, 'tag1', 1);
INSERT INTO tags (id, tag, product_id)
values (2, 'tag2', 1);
INSERT INTO tags (id, tag, product_id)
values (3, 'tag3', 1);
INSERT INTO tags (id, tag, product_id)
values (4, 'tag4', 2);
INSERT INTO tags (id, tag, product_id)
values (5, 'tag5', 3);
Похоже, что ваш пост в основном состоит из кода; пожалуйста, добавьте еще несколько деталей.
Похоже, что ваш пост в основном состоит из кода; пожалуйста, добавьте еще несколько деталей.
Похоже, что ваш пост в основном состоит из кода; пожалуйста, добавьте еще несколько деталей.
Похоже, что ваш пост в основном состоит из кода; пожалуйста, добавьте еще несколько деталей.
Комментарии:
1. Первое, что я вижу, вы не должны очищать свои теги сущностей. Просто зациклите его и обновите входящими данными (но не трогайте идентификаторы). Если вы хотите добавить новые теги — просто создайте новые и добавьте их к существующим тегам. Во-вторых, это может быть проблемой стратегии генерации идентификаторов. Вероятно, Hibernate не видит существующий идентификатор (1) и пытается начать свою собственную последовательность с начала, которое тоже равно 1… Иногда это случается, особенно если вы заполняете таблицы образцами данных вручную или с помощью таких инструментов, как liquibase.
2. У меня есть файл data.sql
Ответ №1:
Пожалуйста, попробуйте вставить, получив таким образом значение следующего идентификатора:
INSERT INTO products (id, name, price, added)
values (
SELECT setval(pg_get_serial_sequence('products', 'id'), coalesce(max(id) 1, 1), false) FROM products,
'Second product',
200,
'2010-10-11'
);