【问题标题】:ADD CONSTRAINT in Hibernate tutorial在 Hibernate 教程中添加约束
【发布时间】:2016-06-17 19:12:36
【问题描述】:

这个例子来自JBOSS的hibernate教程。链接在那里: http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#embeddables.

示例 79. 单向 @OneToMany 关联

@Entity(name = "Person")
public static class Person {

    @Id
    @GeneratedValue
    private Long id;
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Phone> phones = new ArrayList<>();

    public Person() {
    }

    public List<Phone> getPhones() {
        return phones;
    }
}

@Entity(name = "Phone")
public static class Phone {

    @Id
    @GeneratedValue
    private Long id;

    private String number;

    public Phone() {
    }

    public Phone(String number) {
        this.number = number;
    }

    public Long getId() {
        return id;
    }

    public String getNumber() {
        return number;
    }
}
CREATE TABLE Person (
    id BIGINT NOT NULL ,
    PRIMARY KEY ( id )
)

CREATE TABLE Person_Phone (
    Person_id BIGINT NOT NULL ,
    phones_id BIGINT NOT NULL
)

CREATE TABLE Phone (
    id BIGINT NOT NULL ,
    number VARCHAR(255) ,
    PRIMARY KEY ( id )
)

ALTER TABLE Person_Phone
ADD CONSTRAINT UK_9uhc5itwc9h5gcng944pcaslf
UNIQUE (phones_id)

ALTER TABLE Person_Phone
ADD CONSTRAINT FKr38us2n8g5p9rj0b494sd3391
FOREIGN KEY (phones_id) REFERENCES Phone

ALTER TABLE Person_Phone
ADD CONSTRAINT FK2ex4e4p7w1cj310kg2woisjl2
FOREIGN KEY (Person_id) REFERENCES Person

我的问题是,在这个例子中:

1) 为什么 ADD CONSTRAINT 看起来像机器生成的字符串“FKr38us2n8g5p9rj0b494sd3391”?不应该用更有意义的约束手动创建吗?

2) 在这种情况下,ADD CONSTRAINT 是可选的吗?

【问题讨论】:

    标签: java hibernate jboss


    【解决方案1】:

    为什么 ADD CONSTRAINT 看起来像机器生成的字符串, “FKr38us2n8g5p9rj0b494sd3391”?不应该使用手动创建 更有意义的约束?

    当然,约束不是由数据库生成的。它是由 Hibernate 生成的。

    这个奇怪的名字FKr38us2n8g5p9rj0b494sd3391 是由于某些数据库中的约束名称长度限制而产生的。例如,在 Oracle 数据库中,它不能超过 30 个符号长度。

    Hibernate 通过连接表和属性名称生成一个约束名称,并将结果转换为MD5,生成类似FKr38us2n8g5p9rj0b494sd3391 的字符串。此代码 sn-p 来自 Hibernate 源码

    /**
     * Hash a constraint name using MD5. Convert the MD5 digest to base 35
     * (full alphanumeric), guaranteeing
     * that the length of the name will always be smaller than the 30
     * character identifier restriction enforced by a few dialects.
     *
     * @param s The name to be hashed.
     *
     * @return String The hashed name.
     */
    public String hashedName(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance( "MD5" );
            md.reset();
            md.update( s.getBytes() );
            byte[] digest = md.digest();
            BigInteger bigInt = new BigInteger( 1, digest );
            // By converting to base 35 (full alphanumeric), we guarantee
            // that the length of the name will always be smaller than the 30
            // character identifier restriction enforced by a few dialects.
            return bigInt.toString( 35 );
        }
        catch ( NoSuchAlgorithmException e ) {
            throw new HibernateException( "Unable to generate a hashed name!", e );
        }
    }
    

    您可以使用ImplicitNamingStrategy 生成自己的约束名称(唯一和外键)。你可以参考Hibernate5NamingStrategy ,例如。

    还可以使用@ForeignKey@JoinColumn 注释来指定约束名称(通常情况下)。

    在连接表的情况下,您可以使用@JoinTable 注释,正如@uditkhare 建议的那样。但是你需要提供更多的信息(不是很方便)

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinTable(name="person_phones", 
        joinColumns = @JoinColumn(name = "f_person_pid", foreignKey = @ForeignKey(
                name = "fk_person_phones_person")), 
        inverseJoinColumns = @JoinColumn(name = "fk_phone",
                foreignKey = @ForeignKey(name = "fk_person_phones_phone")),
                uniqueConstraints = @UniqueConstraint(name = "uk_person_phones_phone",
                columnNames = { "fk_phone" }))
    private List<Phone> phones = new ArrayList<>();
    

    在这种情况下,ADD CONSTRAINT 是可选的吗?

    没有。这不是可选的。需要建模@OneToMany 关系。

    【讨论】:

      【解决方案2】:

      是的,仅由休眠生成。

      如果你想自己定义,你可以使用如下的东西:

      @OneToMany
      @JoinTable(uniqueConstraints=@UniqueConstraint(name="my_unique_key", columnNames={"phones_id"}))
      

      【讨论】:

      • 您的意思是 3 'create table' 语句是由开发人员制作的,但“Alter table”是由 DB 添加的。所以在本教程中,如果我想尝试本教程,我只需要定义两个类和创建表,而无需担心“更改表”。对吗?
      • @user697911 所有模式创建脚本都是由 Hibernate 生成的,而不是由数据库生成的。看我的回答。
      • @user697911 - 创建表语句也由 hibernate 生成。你只需要创建模型类(或映射xml,如果使用xml方法),所有的ddl都将由hibernate根据“hbm2ddl”属性生成
      • @uditkhare 您应该在@JoinTable 中提供更多信息。例如,我不确定 Hibernate 是否生成 phones_id 列名。当然,my_unique_key 应该是表空间中唯一的名称。
      • @v.ladynev 是的,我刚刚在上面给出了一个基本的想法。它应该类似于 - @JoinTable(name = "Person_Phone" , joinColumns = { @JoinColumn(name = "Person_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name ="phones_id", referencedColumnName = " id") }, uniqueConstraints=@UniqueConstraint(name="my_unique_key", columnNames={"phones_id"}) )
      猜你喜欢
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      相关资源
      最近更新 更多