【问题标题】:ALTER TABLE to add ON DELETE CASCADE statementALTER TABLE 添加 ON DELETE CASCADE 语句
【发布时间】:2012-07-16 23:27:14
【问题描述】:

我想在 PostgreSQL 中执行以下操作(使用 Hibernate):

 ALTER TABLE fruits ADD CONSTRAINTS id ON DELETE CASCADE;

显然,我上面的代码不起作用,所以我正在寻找正确的语句。

如果我不能这样做,那么以下内容如何:

我的表 fruits 中有一堆数据。 fruits 中的id 字段被表grapes 用作外键。我需要删除fruits 中的特定行,并且我希望删除级联到grapes 并删除grapes 中具有指定id 的所有条目。我该怎么做?

delete from fruits where id = 1 cascade; 

注意:我不想加入并删除grape 中的相应数据。这只是一个例子。实际应用中大量表依赖fruits

由于我使用的是Hibernate,对于我使用delete语句的情况,hibernate可以帮忙吗?
或者我可以使用 PostgreSQL 中的信息架构或系统目录来执行此操作吗?

【问题讨论】:

    标签: hibernate postgresql cascade cascading-deletes postgresql-9.0


    【解决方案1】:

    动机

    这对我不起作用,我设置了

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

    并且输出没有说明...ON DELETE CASCADE...之类的内容。

    我找到了另一个对我有用的解决方案:

    假设您有一个作者类和一个作者书籍类,并且您希望在删除作者时自动删除所有书籍(通过 hibernate、sql-query ......)并且您不能(总是) 通过 session.delete() 删除。

    也许:

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

    解决方案

    所以你的作者类可能看起来像这样:

    @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;
    ...
    

    课本看起来像这样:

    @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;
    ...
    

    诀窍是使用您自己的外键约束命名

    foreignKey = @ForeignKey(name = "FK_BOOK_author_AUTHOR_ID")
    

    然后添加

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

    到您的 hibernate.cfg.xml(不要忘记 hibernate.hbm2ddl.auto)。 update.sql 然后包含表约束的更新:

    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;
    

    所以 hibernate 总是能够删除/更改约束,因为它知道约束的名称——你还应该检查 @Cascade 设置——你必须实施一个策略来处理你的对象的删除会议!

    【讨论】:

      【解决方案2】:

      我找到了答案:

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

      【讨论】:

        【解决方案3】:

        你描述的是教科书foreign key constraint使用ON DELETE CASCADE选项。

        SQL 中,您可以在您的场景中创建表 grapes 时隐式创建它:

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

        或者您可以稍后添加:

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

        您不会直接为此编辑系统目录 - 您几乎从不这样做!这就是上述DDL 语句的用途。

        请注意,外键约束需要引用列上的唯一索引或主索引(在您的情况下为fruits.fruit_id)并强制执行referential integrity

        【讨论】:

          【解决方案4】:

          这是一种单向的父子关系,您希望父级的更改向下级联到子级,反之则不行。使用注解,我们可以做到这一点。在fruits 实体中:

          @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;
          }
          

          在“葡萄”实体中:

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

          当您更新或删除父 fruit 时,更改将自动级联到 grape 子代。

          【讨论】:

          • 在 Fruit POJO 中,我是否必须创建一个字段 grapes,如 private Set&lt;Grape&gt; grapes; 没有注释?孩子的父母也一样吗?
          • 是的。以上是对getter的注解;你仍然需要这些字段
          • 在回来之前,我尝试自己做很多事情,只是想看看你的帖子是否有一个版本可以工作。但它没有奏效。首先它抱怨Could not determin type for:java.util.Set, at table: Fruit,for column(grapes);然后当我将@ManyToOne 添加到Set&lt;Grape&gt; grapes 字段时,它说缺少表Fruit_Grape。仍然感谢您的发帖。
          • 发布您的实体代码。您似乎遗漏了一些东西。
          猜你喜欢
          • 2010-12-06
          • 1970-01-01
          • 2016-09-28
          • 1970-01-01
          • 2011-09-04
          • 2021-04-01
          • 2015-12-31
          • 1970-01-01
          相关资源
          最近更新 更多