How to define in Liquibase a set of default column

2019-05-10 19:51发布

问题:

I just looking around to reduce effort and errors on table creation on liquibase.

Is it possible to create a set of default colums for tables?

columns:

  • int ID
  • varchar UUID
  • timestamp createdTs
  • timestamp updatedTs
  • int lockVersion

constraints

  • ID not NULL and with autogenerated key (as primary key)
  • UUID not NULL
  • createdTS not NULL with default CURRENT_TIMESTAMP
  • updatedTS not NULL with default CURRENT_TIMESTAMP
  • lockVersion not NULL

index

  • ID
  • UUID

so for example: genericTable.xml

<changeSet author="me" id="myCsId">
   <column name="id" type="int" />
   <column name="uuid" type="varchar(255)" />
   <column name="rowCreated" type="datetime" />
   <column name="rowUpdated" type="datetime" />
   <addNotNullConstraint columnName="id" schemaName="${schema}" tableName="???" columnDataType="int" />
   <addNotNullConstraint columnName="uuid" schemaName="${schema}" tableName="???" columnDataType="varchar(255)" />
   <addNotNullConstraint columnName="rowCreated" schemaName="${schema}" tableName="???" columnDataType="timestamp" />
   <addNotNullConstraint columnName="rowUpdated" schemaName="${schema}" tableName="???" columnDataType="timestamp" />
   <addPrimaryKey columnNames="ID" constraintName="pk_myKey" schemaName="${schema}" tableName="???" />
   ....
</changelog>

and now to create a different changelog like:

<changeSet author="me" id="myCrazyLazyTable1">
   <include file="genericTable.xml" /> <!-- how to pass values like myCrazyLazyTable1 to only this included region to replace the above ??? -->
   <column name="anyadditionlColumn" type="int"/>
</changeset>

<changeSet author="me" id="myCrazyLazyTable2">
   <include file="genericTable.xml" /> <!-- how to pass values like myCrazyLazyTable2 to only this included region to replace the above ??? -->
   <column name="anyadditionlColumn" type="int"/>
</changeset>

can someone help me out of the dark?

回答1:

I got some hints, but could not solve the issue with the hints. So I had to fiddle around to get to following solution. Since I like full examples here a running example. The example shows how to create a reusable default table structure for default columns and default contraints.

my MasterChangelog.xml referencing the changesets/changelogs

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd
        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

   <!-- You can replace the XML-files between the brackets with your XML-files. -->
   <!-- Caution! You have to save your XML-files in the same Folder that contains the MasterChangelog.xml -->

   <include relativeToChangelogFile="true"  file="001_CreateTranslations.xml" />

</databaseChangeLog>

now the changelog itself the 001_CreateTranslations.xml. It reuses the template Table 000_DefaultTable.xml and also some reusable properties in 000_DefaultProperties.dtd. So this example creates in the first changeset the default table structure with the wished table name and in the second changeset the create of an additional column with addColumn xml tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE defaultProperties SYSTEM "000_DefaultProperties.dtd">
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <!-- include the default properties -->
    &propertiesAll;

    <property name="table.schema" value="${schema}" />
    <property name="table.name" value="Translations" />
    <property name="table.author" value="cilap" />
    <property name="changeset.number" value="001" />
    <property name="changeset.operation" value="Create" />
    <property name="changeset.name" value="${changeset.number}_${changeset.operation}${table.name}" />

    <!-- create default table ${table.name} -->
    <include file="000_DefaultTable.xml" relativeToChangelogFile="true" />

    <changeSet author="${table.author}" id="${changeset.name}">
        <addColumn schemaName="${schema}" tableName="${table.name}">
            <column name="country" type="VARCHAR(255)" />
        </addColumn>
    </changeSet>
</databaseChangeLog>

my XML entities are in 000_DefaultProperties.dtd

<!ENTITY propertyNow "
   <property name='now' value='sysdate' dbms='oracle' />
   <property name='now' value='now()' dbms='mysql' />
   <property name='now' value='CURRENT_TIMESTAMP' dbms='h2' />
   <property name='now' value='CURRENT_TIMESTAMP' dbms='postgresql' />
" >
<!ENTITY propertySchema "
   <property name='schema' value='redd' dbms='mysql' />
   <property name='schema' value='PUBLIC' dbms='h2' />
" >
<!ENTITY propertiesAll "&propertySchema; &propertySchema;" >

and my default/template table is 000_DefaultTable.xml

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext 
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <!-- default changeset for a standard table to use -->
    <!-- set the properties -->
    <!-- <property name="table.schema" value="${schema}" /> -->
    <!-- <property name="table.name" value="Translations" /> -->
    <!-- <property name="table.author" value="cilap" /> -->
    <!-- <property name="changeset.number" value="001" /> -->
    <!-- <property name="changeset.operation" value="Create" /> -->
    <!-- <property name="changeset.name" value="${changeset.number}_${changeset.operation}${table.name}" /> -->

    <changeSet author="${table.author}" id="${changeset.name}Default">
        <createTable schemaName="${table.schema}" tableName="${table.name}">
            <column name="Id" type="int" />
            <column name="Uuid" type="varchar(255)" />
            <column name="RowCreated" type="datetime" />
            <column name="RowUpdated" type="datetime" />
        </createTable>

        <!-- mandatory not null constraints on default columns -->
        <addNotNullConstraint columnName="Id" schemaName="${table.schema}" tableName="${table.name}" columnDataType="int" />
        <addNotNullConstraint columnName="Uuid" schemaName="${table.schema}" tableName="${table.name}" columnDataType="varchar(255)" />
        <addNotNullConstraint columnName="RowCreated" schemaName="${table.schema}" tableName="${table.name}"
        columnDataType="datetime" />
        <addNotNullConstraint columnName="RowUpdated" schemaName="${table.schema}" tableName="${table.name}"
        columnDataType="datetime" />

        <!-- create primary key -->
        <addPrimaryKey columnNames="Id" constraintName="pk_${table.name}" schemaName="${table.schema}" tableName="${table.name}" />
        <addAutoIncrement tableName="${table.name}" columnName="Id" columnDataType="int" />

        <!-- create unique index on uuid -->
        <createIndex indexName="Idx${table.name}Uuid" schemaName="${table.schema}" tableName="${table.name}" unique="true">
            <column name="Uuid" type="varchar(255)" />
        </createIndex>
    </changeSet>
</databaseChangeLog>


回答2:

There is nothing built into Liquibase to support this.

Your easiest option would be to use XML document entities which is purely XML-level and therefore transparent to Liquibase. They would allow you to attach common XML into your changelog files.

A more complex approach would be to use the Liquibase extension system (http://liquibase.org/extensions) which allows you to redefine the logic to convert changeSets into SQL. That would allow you to inject any logic you want, including common data types, standard columns, or anything else.