在MySQL中使用DDL模式生成时ON DELETE CASCADE选项不产生(ON DELETE

2019-08-04 13:08发布

在Maven的Spring的Hibernate的MySQL的在Tomcat Web应用程序运行,我使用Hibernate的DDL生成我的MySQL5InnoDBDialect DB模式。

该模式产生除了外国键级联选项就好了。 例如,我有这样的结构:

保存用户信息的用户对象的对象,都共享同一个密钥:

@Entity
@Table(name = "Users")
public class User implements Serializable {

    private static final long serialVersionUID = -359364426541408141L;

    /*--- Members ---*/

    /**
     * The unique generated ID of the entity.
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "User_Id")
    protected long id;

    @Getter
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user", optional = true)
    protected UserDetails userDetails;

...

}

和用户的详细信息:

@Entity
@Table(name = "UserDetails")
public class UserDetails implements Serializable {

    private static final long serialVersionUID = 957231221603878419L;

    /*--- Members ---*/

    /**
     * Shared Key
     */
    @Id
    @GeneratedValue(generator = "User-Primary-Key")
    @GenericGenerator(name = "User-Primary-Key", strategy = "foreign", parameters = { @Parameter(name = "property", value = "user") })
    @Column(name = "User_Id")
    protected long id;

    @Getter
    @Setter
    @OneToOne(optional = false, fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
    private User user;

...

}

当生成模式,从用户的细节表用户表的外键缺少级联。

下面是模式创建的用户的详细信息:

CREATE TABLE `userdetails` (
  `User_Id` bigint(20) NOT NULL,
  `Creation_Time` bigint(20) NOT NULL,
  `EMail` varchar(128) DEFAULT NULL,
  `Enabled` bit(1) NOT NULL,
  `First_Name` varchar(15) DEFAULT NULL,
  `Last_Name` varchar(25) DEFAULT NULL,
  `Password` varchar(64) NOT NULL,
  `User_Name` varchar(15) NOT NULL,
  PRIMARY KEY (`User_Id`),
  UNIQUE KEY `User_Name` (`User_Name`),
  UNIQUE KEY `EMail` (`EMail`),
  KEY `FKAE447BD7BF9006F5` (`User_Id`),
  CONSTRAINT `FKAE447BD7BF9006F5` FOREIGN KEY (`User_Id`) REFERENCES `users` (`User_Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

正如你所看到的没有任何“ON DELETE CASCADE”的“主键”一节中写到那里。

这个问题也被描述在这里和这里为好。

所以,我想加入上面没有运气的为userDetails成员@OnDelete注解..

然后我创建了自己的方言重写supportsCascadeDelete:

public class MySql5Dialect extends MySQL5InnoDBDialect {

    public MySql5Dialect() {
    super();
    }

    @Override
    public String getTableTypeString() {
    return " ENGINE=InnoDB DEFAULT CHARSET=utf8";
    }

    @Override
    public boolean supportsCascadeDelete() {
    return true;
    }

}

但仍然没有改变。 我的外键级联选项仍然设置生成模式后,“限制”:

有没有办法解决这个问题(非手动的过程)的方法吗?

UPDATE

继天使Villalain的建议,我把@OnDelete注释以上的UserDetails类的‘用户’成员,这确实为OneToOne关系的伎俩,删除级联,但的OnUpdate设置为限制(仍然),这导致我对我的第一个问题 - 是什么那是什么意思? 我的意思是“OnDelete”是非常简单的 - 当我删除父删除子为好,但什么是“的OnUpdate”选项的含义? 它是如何影响我的应用程序时,将其设置为限制/级联?

我的第二个问题是指具有一对多的关系级联。 我的User类hols许多UserProviders。 以下代码是从用户类:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "Users_Providers", joinColumns = @JoinColumn(name = "User_Id"), inverseJoinColumns = @JoinColumn(name = "Provider_Id"))
protected Set<UserProvider> userProviders = new HashSet<>(0);

这是反比关系,从UserProvider类:

@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "Users_Providers", joinColumns = @JoinColumn(name = "Provider_Id", insertable = false, updatable = false), inverseJoinColumns = @JoinColumn(name = "User_Id"))
@OnDelete(action = OnDeleteAction.CASCADE)
protected User user;

因此,使用@OnDelete注解我期望看到与级联连接表的onDelete选项后,但它不是:(我有没有正确使用呢?

最后一个问题 - 关于单向关系如@ElementCollection什么? 我的UserDetails类保持角色(每个用户可以与一个或多个角色被分配)的ElementCollection:

@ElementCollection(fetch = FetchType.EAGER, targetClass = Role.class)
@CollectionTable(name = "Users_Roles", joinColumns = @JoinColumn(name = "User_Id", referencedColumnName = "User_Id"))
@Column(name = "Role")
protected Set<Role> roles = new HashSet<Enums.Role>(0);

一个角色仅仅是一个枚举,而不是一个实体,因此我不能从角色到父实体点背。 在这种情况下,是有办法级联onDelete?

Answer 1:

随着OnDelete注释的DDL应该是正确的。 你可以检查你是如何配置SessionFactory您使用的hbm2ddl.auto参数,该参数值,在具体的。

UPDATE

  • 关于与您的问题UserProvider类。 首先映射似乎是双向的,但一方必须是业主方,另一个必须是反方。 这意味着拥有关系的一个是持续的关系到连接表的一个,另一个必须与被映射mappedBy参数,不控制的关系。 所以, OneToManymappedBy指向user的成员UserProperty将是反方,而UserProperty将是业主方,而且应该是OnDelete注解。 但让我测试它明天可以肯定的,我不是在我的dev站前。


Answer 2:

调查这个问题后,我想出了以下的方法来处理数据库架构代(假设你正在使用Hibernate作为JPA提供者):

  • 使用DDL模式生成,可以生成你的DB模式。 使用此选项的模式将被创建/更新,而你开始你的Web服务器。 如果您使用此方法,以确保您的onDelete选项设置为级联可以使用OnDelete注解。 这为我工作就好了OneToOne关系(感谢天使Villalain ),但由于某种原因,没有为一对多关系的工作。 要解决这个差距我用Spring的ResourceDatabasePopulator :

在DB-additions.sql文件包含了适应我的数据库,在我的情况下创建Ondelete级联查询。 例如:

ALTER TABLE `buysmartdb`.`users_providers` DROP FOREIGN KEY `FKB4152EEBBF9006F5` ;
ALTER TABLE `buysmartdb`.`users_providers` 
  ADD CONSTRAINT `FKB4152EEBBF9006F5`
  FOREIGN KEY (`User_Id` )
  REFERENCES `buysmartdb`.`users` (`User_Id` )
  ON DELETE CASCADE
  ON UPDATE CASCADE;

注意的是Hibernate的DDL,这是很好的生成架构后,由ResourceDatabasePopulator触发脚本适用。 我知道,sinply由于最终的结果,我真的无法确保它得到了保证。

  • 第二种方法是为使用行家模式,在编译时。 有这样做的一些方法,比如这一个或那一个。

我希望这会帮助别人..



Answer 3:

出于某种原因,把@OnDelete在MySQL和PostgreSQL中并没有为我工作@ManyToOne的一面,但它的工作的@OneToMany侧。 https://stackoverflow.com/a/44988100/4609353



文章来源: ON DELETE CASCADE option not in generated when using ddl schema generation on Mysql