ALTER TABLE to add ON DELETE CASCADE statement

落爺英雄遲暮 提交于 2019-12-11 18:48:45

问题


I want to do the following in PostgreSQL (using Hibernate):

 ALTER TABLE fruits ADD CONSTRAINTS id ON DELETE CASCADE;

Obviously, my code above is not working, so I am looking for the correct statement.

If I can't do that, then how about the following:

I have a bunch of data in my table fruits. The id field in fruits is used as a foreign key by table grapes. I need to delete a specific row in fruits and I want the deletion to cascade to grapes and delete all entries in grapes that has the specified id. How do I do that?

delete from fruits where id = 1 cascade; 

NOTE: I don't want to do a join and delete the corresponding data in grape. This is just an example. In the real application a large number of tables depend on fruits.

Since I am using Hibernate, for the case when I use a delete statement, can hibernate help do it?
Or can I do this with the information schema or system catalog in PostgreSQL?


回答1:


What you describe is the textbook foreign key constraint using the ON DELETE CASCADE option.

In SQL you can create it implicitly when creating the table grapes in your scenario:

CREATE TABLE grapes (
  grape_id int PRIMARY KEY
  fruit_id int REFERENCES fruits(fruit_id) ON DELETE CASCADE
  );

Or you can add it later:

ALTER TABLE grapes
ADD CONSTRAINT grapes_fruit_id_fkey FOREIGN KEY (fruit_id)
REFERENCES fruits (fruit_id) ON DELETE CASCADE;

You don't edit the system catalogs directly for that - you hardly ever do! That is what DDL statements like the above are for.

Be aware that a foreign key constraint requires a unique or primary index on the referenced column (fruits.fruit_id in your case) and enforces referential integrity.




回答2:


This is a unidirectional parent-child relationship, where you want a change at the parent to cascade down to the child, but not vice versa. Using annotations, we can accomplish this. In the fruits entity:

@Cascade(value = { org.hibernate.annotations.CascadeType.ALL, 
    org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
@OneToMany(fetch = FetchType.LAZY, mappedBy = "fruit")
public Set<Grape> getGrapes() {
    return grapes;
}

In the 'grape' entity:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fruit_id")
public Fruit getFruit() {
    return fruit;
}

When you update or delete the parent fruit, the change will automatically cascade to the grape children.




回答3:


I found the answer:

    //in Fruit object
    @OneToMany(mappedBy = "fruit", orphanRemoval=true)
    private List<Grape> grapes;

   //in Grape object
   @OneToOne
   private Fruit fruit;



回答4:


Motivation

This did not work for me, I set

<property name="show_sql">true</property> 

and the output did not state anything like ...ON DELETE CASCADE....

I found another solution which worked for me:

Lets assume you have a class for authors and a class for the author's books and you want to auto delete all books whenever you delete the author (via hibernate, sql-query, ...) and there's reasons you cannot (always) delete via session.delete().

Maybe:

session.createSQLQuery("DELETE FROM author").executeUpdate();

Solution

So your author class may look like this:

@Entity
@Table(name = "author")
public class Author {

   @Id
   @GeneratedValue(generator = "increment")
   @GenericGenerator(name = "increment", strategy = "increment")
   @Column(name = "ID")
   private Integer id;

   @Column(name = "NAME")
   private String name;

   @OneToMany(mappedBy = "author")
   private Set<Book> books;
...

and the class book looks like this:

@Entity
@Table(name = "book")
public class Book {

   @Id
   @GeneratedValue(generator = "increment")
   @GenericGenerator(name = "increment", strategy = "increment")
   @Column(name = "ID")
   private Integer id;

   @Column(name = "TITLE")
   private String title;

   @ManyToOne
   @JoinColumn(name = "AUTHOR_ID", foreignKey = @ForeignKey(name = "FK_BOOK_author_AUTHOR_ID"))
   private Author author;
...

The trick is to name the foreign key constraints on your own using

foreignKey = @ForeignKey(name = "FK_BOOK_author_AUTHOR_ID")

and then add

<property name="hibernate.hbm2ddl.import_files">update.sql</property>

to your hibernate.cfg.xml (dont forget hibernate.hbm2ddl.auto). The update.sql then contains the update of the table constraints:

ALTER TABLE `book` DROP FOREIGN KEY `FK_BOOK_author_AUTHOR_ID`; 
ALTER TABLE `book` ADD CONSTRAINT `FK_BOOK_author_AUTHOR_ID` FOREIGN KEY (`AUTHOR_ID`) REFERENCES `author`(`ID`) ON DELETE CASCADE;

So hibernate is always able to drop/change the constraints because it knows the name of the constraints - you should also check the @Cascade settings - and you have to implement a strategy on how you handle the deletion of the objects in your session!



来源:https://stackoverflow.com/questions/11532711/alter-table-to-add-on-delete-cascade-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!