package jef.database.meta; import java.lang.annotation.Annotation; import java.sql.DatabaseMetaData; import javax.persistence.Column; import javax.persistence.ConstraintMode; import org.apache.commons.lang.StringUtils; import jef.database.dialect.DatabaseDialect; import jef.database.support.RDBMS; /** * 描述外键信息 * * @author Administrator * */ public class ForeignKey implements javax.persistence.ForeignKey{ // 删除被引用的记录引发的策略,默认为禁止删除,不同数据库的返回值常量不同 @Column(name = "FKTABLE_SCHEM") private String fromSchema; @Column(name = "FKTABLE_NAME") private String fromTable; @Column(name = "FKCOLUMN_NAME") private String fromColumn; @Column(name = "PKTABLE_SCHEM") private String referenceSchema; @Column(name = "PKTABLE_NAME") private String referenceTable; @Column(name = "PKCOLUMN_NAME") private String referenceColumn; @Column(name = "KEY_SEQ") private int keySeq; /** * 删除规则:当被引用的数据删除时:<br> * 默认: 禁止删除/on delete cascade: 删除那些引用此记录的记录/ on delete set null: * 清空那些引用此记录的字段 * <ul> * <li>importedKeyNoAction - do not allow delete of primary key if it has * been imported</li> * <li>importedKeyCascade - delete rows that import a deleted key</li> * <li>importedKeySetNull - change imported key to NULL if its primary key * has been deleted</li> * <li>importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x * compatibility)</li> * <li>importedKeySetDefault - change imported key to default if its primary * key has been deleted</li> * </ul> */ @Column(name = "DELETE_RULE") private int deleteRule;// /** * 更新规则:当被引用的记录键值更新时<br> * 默认:禁止更新 /on update cascade: 删除那些引用此记录的记录<br> * 注意:Oracle不支持此操作,因此Oracle驱动返回的值总是0 * <ul> * <li>importedNoAction - do not allow update of primary key if it has been * imported</li> * <li>importedKeyCascade - change imported key to agree with primary key * update</li> * <li>importedKeySetNull - change imported key to NULL if its primary key * has been updated</li> * <li>importedKeySetDefault - change imported key to default values if its * primary key has been updated</li> * <li>importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x * compatibility)</li> * </ul> */ @Column(name = "UPDATE_RULE") private int updateRule; /** * 外键名称 */ @Column(name = "FK_NAME") private String name; /** * 主键名称 */ @Column(name = "PK_NAME") private String pkName;// ?? /** * Initially immediate(default) - constraint validated at statement level * Initially deferred - constraint validated at commit level */ @Column(name = "DEFERRABILITY") private int deferrAbility; public ForeignKey() { } public ForeignKey(String table, String column, String refTable, String refColumn) { this.fromTable = table; this.fromColumn = column; this.referenceTable = refTable; this.referenceColumn = refColumn; } public String getFromTable() { return fromTable; } public void setFromTable(String fromTable) { this.fromTable = fromTable; } public String getFromColumn() { return fromColumn; } public void setFromColumn(String fromColumn) { this.fromColumn = fromColumn; } public String getReferenceTable() { return referenceTable; } public void setReferenceTable(String referenceTable) { this.referenceTable = referenceTable; } public String getReferenceColumn() { return referenceColumn; } public void setReferenceColumn(String referenceColumn) { this.referenceColumn = referenceColumn; } public int getKeySeq() { return keySeq; } public void setKeySeq(int keySeq) { this.keySeq = keySeq; } public int getDeleteRule() { return deleteRule; } public void setDeleteRule(int deleteRule) { this.deleteRule = deleteRule; } public int getUpdateRule() { return updateRule; } public void setUpdateRule(int updateRule) { this.updateRule = updateRule; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPkName() { return pkName; } public void setPkName(String pkName) { this.pkName = pkName; } public int getDeferrAbility() { return deferrAbility; } public void setDeferrAbility(int deferrAbility) { this.deferrAbility = deferrAbility; } public String getFromSchema() { return fromSchema; } public void setFromSchema(String fromSchema) { this.fromSchema = fromSchema; } public String getReferenceSchema() { return referenceSchema; } public void setReferenceSchema(String referenceSchema) { this.referenceSchema = referenceSchema; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(name).append("("); sb.append(fromTable).append('.').append(fromColumn); sb.append("->").append(referenceTable).append('.') .append(referenceColumn).append(')'); sb.append("D:").append(this.deleteRule); sb.append("U:").append(this.updateRule); sb.append("F:").append(this.deferrAbility); return sb.toString(); } /** * 生成删除外键的SQL语句 * * @return */ public String toDropSql() { StringBuilder sb = new StringBuilder(); sb.append("alter table ").append(fromTable).append(" drop constraint ") .append(name); return sb.toString(); } /** * 生成修改表增加外键的SQL语句 * * @return */ public String toCreateSql(DatabaseDialect dialect) { StringBuilder sb = new StringBuilder(); sb.append("alter table ").append(getTableName()) .append(" add constraint ").append(name==null?generate():name); sb.append(" foreign key (").append(fromColumn).append(") references "); sb.append(referenceTable).append('(').append(referenceColumn) .append(')'); if(dialect.getName()==RDBMS.oracle){ if (this.deleteRule == DatabaseMetaData.importedKeyCascade) { sb.append(" on delete cascade"); // on delete cascade: 删除那些引用此记录的记录 } else if (deleteRule == DatabaseMetaData.importedKeySetNull) { sb.append(" on delete set null");// on delete set null: 清空那些引用此记录的字段 } if (this.updateRule == DatabaseMetaData.importedKeyCascade) { sb.append(" on update cascade");// ON UPDATE CASCADE : // 更新时也更新那些引用此字段的记录 } else if (this.updateRule == DatabaseMetaData.importedKeySetNull) { sb.append(" on update set null");// ON UPDATE CASCADE : // 更新时也更新那些引用此字段的记录 } } if (this.deferrAbility == DatabaseMetaData.importedKeyInitiallyDeferred) { sb.append(" initially deferred"); } else if (this.deferrAbility == DatabaseMetaData.importedKeyInitiallyImmediate) { sb.append(" Initially immediate"); } return sb.toString(); } private String generate() { StringBuilder sb=new StringBuilder("FK_"); sb.append(StringUtils.upperCase(fromTable)).append('_'); sb.append(StringUtils.upperCase(fromColumn)); return sb.toString(); } private String getTableName() { if (fromSchema != null) { return fromSchema + "." + fromTable; } else { return fromTable; } } @Override public Class<? extends Annotation> annotationType() { return javax.persistence.ForeignKey.class; } @Override public String name() { return this.name; } @Override public ConstraintMode value() { return ConstraintMode.CONSTRAINT; } @Override public String foreignKeyDefinition() { return this.toString(); } }