Java Коллекция элементов каскада пружин удалить - PullRequest
6 голосов
/ 29 апреля 2020

По какой-то причине мое удаление не является каскадным, когда я пытаюсь удалить родительский элемент, в котором есть коллекция элементов, следующие два класса:

@Entity
@Table(name="Timestamps")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ProductList {
    private boolean success;
    @Id
    private Date lastUpdated;

    private String time = "minute";

    @ElementCollection
    @MapKeyColumn(name="product_id")
    @CollectionTable(name="Products")
    private Map<String,Product> products;

И:

@Embeddable
@JsonIgnoreProperties(ignoreUnknown = true)
public class Product{
    @Embedded
    private Status quick_status;

В настоящее время это единственное поле, которое у меня есть в классе, потому что я удалил все остальные, пытаясь выяснить, почему при попытке удалить родительский объект удаление не происходит каскадно в таблице Products. Ниже приведен запрос, который я выполняю:

DELETE FROM Timestamps list WHERE list.last_updated !=0;

Значение last_updated всегда будет отличным от нуля, поэтому я просто использую этот запрос для проверки удаления, но даже когда я запускаю запрос в mysql Оболочка я получаю "Не удается удалить или обновить родительскую строку: ограничение внешнего ключа не удается" Я подумал, что аннотация elementcollection должна была автоматически каскадно, есть что-то, что мне не хватает?

EDIT, когда ниже приведены sql Команды, которые отправляет Hibernate, как вы заметите, на третьей отсутствует каскад.

Hibernate: create table products (product_list_last_updated datetime(6) not null, buy_price float not null, sell_price float not null, product_id varchar(255) not null, primary key (product_list_last_updated, product_id)) engine=InnoDB
Hibernate: create table timestamps (last_updated datetime(6) not null, success bit not null, time varchar(255), primary key (last_updated)) engine=InnoDB
Hibernate: alter table products add constraint FKo31ur4gpvx1d5720rgs3qaawi foreign key (product_list_last_updated) references timestamps (last_updated)

РЕДАКТИРОВАТЬ 2: Ниже приведен @Query, который я имею для класса ProductListRepository, который я включил на запрос, который имеет отношение к удалению.

@Repository
public interface ProductListRepository extends CrudRepository<ProductList, Integer>{
    @Modifying
    @Query(value = "DELETE FROM Timestamps list WHERE list.last_updated !=0", nativeQuery = true)
    void deleteOld();
}

Ответы [ 3 ]

0 голосов
/ 02 мая 2020

Есть несколько переменных в игре. @ElementCollection имеет некоторые ограничения. См .: https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection

Ограничения использования ElementCollection вместо OneToMany заключаются в том, что целевые объекты нельзя запрашивать, сохранять, объединять независимо от их родительского объекта. Они являются строго частными (зависимыми) объектами, такими же, как встроенное отображение. В ElementCollection отсутствует каскадная опция, целевые объекты всегда сохраняются, объединяются, удаляются вместе со своим родителем. ElementCollection по-прежнему может использовать тип выборки и по умолчанию LAZY, как и другие сопоставления коллекций.

Работает так, как задумано, поскольку productRepository.deleteAll() работает.

Почему нет работать с собственным запросом? Поскольку собственные запросы выполняются «как есть», это означает, что он не будет учитывать аннотации в сущностях.

Additionnaly, поскольку он помечен @ElementCollection не включает ON DELETE CASCADE в constraint foreign key

Ака, этот alter table... не имеет ON DELETE CASCADE

alter table products add constraint FKo31ur4gpvx1d5720rgs3qaawi foreign key (product_list_last_updated) references timestamps (last_updated)

Предлагаемое решение 1

Изменить с @ElementCollection до @OneToMany с предполагаемыми параметрами каскада.

Предлагаемое решение 2

Удалите nativeQuery = true и используйте вместо этого запрос JPA. Он должен выглядеть примерно так:

@Modifying
@Query("DELETE FROM ProductList list WHERE list.lastUpdated != 0")
void deleteOld();

Предлагаемое решение 3

Использование именованных запросов Spring Data в вашем ProductListRepository. Что-то вроде:

deleteByLastUpdatedNot(Date date);
or 
deleteByLastUpdatedLessThan(Date date);
0 голосов
/ 08 мая 2020

В mysql оболочке вы не можете выполнить запрос, потому что вы не установили свой внешний ключ ON DELETE CASCADE в вашем mysql. Добавление ON DELETE CASCADE к вашему внешнему ключу позволит mysql shell каскадно при удалении.

Кажется нелогичным удалять продукт после удаления его журналов.

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

  • CREATE TABLE products (id INT NOT NULL AUTO_INCREMENT, buy_price FLOAT, sell_price FLOAT, lastUpdateDate DATETIME, PRIMARY KEY ( id));
  • CREATE TABLE timestamps (id INT NOT NULL AUTO_INCREMENT, product INT NOT NULL, success BIT NOT NULL, updateDate DATETIME NOT NULL, ПЕРВИЧНЫЙ КЛЮЧ ( id), ИНОСТРАННЫЙ КЛЮЧ (product) ССЫЛКИ products (id) НА УДАЛИТЬ КАСКАД );

Так что теперь, когда вы удаляете продукт, это журналы будут удалены.

0 голосов
/ 02 мая 2020

(Предостережение: я не знаю, что было в голове у дизайнеров.)

Для меня автоматическое c удаление данных страшно. Небольшое недопонимание с моей стороны может привести к удалению данных, которых я не ожидал.

Конечно, в хорошо разработанной схеме в стиле учебника данные будут идеально структурированы, и должно быть очевидно, что удалить и что не удалить.

Но схемы учебников ограничены учебниками.

...