2

I've faced a problem when implementing liquibase in an existing project. So we have two entities:

Company:

@Entity
@Table(name = "company")
@EqualsAndHashCode(of = {}, callSuper = true)
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Company extends AbstractAccount {

    private String organizationName;
    private String mail;
    private Set<Stock> stocks;
    private Stock currentStock;

    @Column(name = "organization_name", unique = true)
    public String getOrganizationName() {
        return organizationName;
    }

    @Email
    @Column(name = "mail", unique = true)
    public String getMail() {
        return mail;
    }

    @Cascade({CascadeType.REMOVE, CascadeType.SAVE_UPDATE})
    @OneToMany(mappedBy = "company", fetch = FetchType.LAZY)
    public Set<Stock> getStocks() {
        return stocks;
    }

    @OneToOne
    @JoinColumn(name = "current_stock_id", referencedColumnName = "id")
    public Stock getCurrentStock() {
        return currentStock;
    } 
}

Stock:

@Entity
@Table(name = "stock")
@EqualsAndHashCode(of = {}, callSuper = true)
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Stock extends AbstractEntity {

    private String name;
    private Company company;
    private Double fare;

    @Column(name = "panel")
    public Double getFare() {
        return fare;
    }

    @NotBlank(message = "Название акции не может быть пустым.")
    @Column(name = "name")
    public String getName() {
        return name;
    }

    @Cascade({CascadeType.SAVE_UPDATE})
    @ManyToOne(fetch = FetchType.LAZY)
    public Company getCompany() {
        return company;
    }

}

And my liquibase changelogs.

Company:

<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

<changeSet id="1" author="Maxim Grankin">
    <createTable tableName="company">
        <column name="id" type="bigint" autoIncrement="true">
            <constraints primaryKey="true" nullable="false"/>
        </column>
    </createTable>
</changeSet>

<changeSet id="2" author="Maxim Grankin">
    <addColumn tableName="company">
        <column name="organizationName" type="varchar(255)">
            <constraints unique="true"/>
        </column>
        <column name="mail" type="varchar(255)">
            <constraints unique="true"/>
        </column>
        <column name="current_stock_id" type="bigint"/>
    </addColumn>
    <addForeignKeyConstraint baseTableName="company" baseColumnNames="current_stock_id"
                             constraintName="fkoi5aq2bm82091ubh15kfj29m1"
                             referencedTableName="stock"
                             referencedColumnNames="id"/>
</changeSet>

Stock:

<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">

<changeSet id="1" author="Maxim Grankin">
    <createTable tableName="stock">
        <column name="id" type="bigint" autoIncrement="true">
            <constraints primaryKey="true" nullable="false"/>
        </column>
    </createTable>
</changeSet>

<changeSet id="2" author="Maxim Grankin">
    <addColumn tableName="stock">
        <column name="name" type="varchar(255)"/>
        <column name="panel" type="double precision"/>
        <column name="company_id" type="bigint"/>
    </addColumn>
    <addForeignKeyConstraint baseTableName="stock" baseColumnNames="company_id"
                             constraintName="fk9r297vk0rghnrccw09x0qybfj"
                             referencedTableName="company"
                             referencedColumnNames="id"/>
</changeSet>

And master:

<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.8.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

<include file="data/changelogs/stock/stock/db.changelog.stock.xml"/>
<include file="data/changelogs/company/db.changelog.company.xml"/>

I have this exception:

Caused by: org.postgresql.util.PSQLException: ERROR: relation "public.company" does not exist

I understand that liquibase trying to create stock and then add company_id as foreign key although there is no company table yet. I have a bunch of bidirectional relationships and this one is only part of them.

Question: How can I organize liquibase changeLogs to create all tables and relationships between them in one build? Should I create something like "db.changelogs.relations" where I will set up foreign keys?

UPD: Closed. Generate your changeLogs with maven plugin for liquibase

gtiwari333
  • 24,554
  • 15
  • 75
  • 102
  • I don't know how you wrote or generated the change log xmls.. but liquibase would generate the change logs for tables first and then the FKs – gtiwari333 Oct 03 '20 at 18:42
  • Use liquibase plugin to generate change logs – gtiwari333 Oct 03 '20 at 18:43
  • See this for an example: https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/orm/pom.xml – gtiwari333 Oct 03 '20 at 18:44
  • https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/orm/src/main/resources/liquibase/changelog/20200810015320_changelog.xml is an example of generated XML. Note how things are ordered – gtiwari333 Oct 03 '20 at 18:44
  • 1
    @gtiwari333 thank you very much! I've never heard about generating change logs and you helped me a lot. – Maxim Grankin Oct 06 '20 at 19:36

2 Answers2

1

Creating Answer out of my Comments on the Question:

It looks you are writing your change log xml manually. If you arrange your change log to put table creation at first and the FKs then it would be fine.

  • Create Table1, Table2, Table3
  • Setup relation between Table1 and Table2, Table2 an Table3

Better option is to use liquibase plugin (for your maven/gradle) to generate such change logs. Liquibase would generate the change logs for tables first and then the FKs so that you don't need to worry about this.

See these as an reference:

gtiwari333
  • 24,554
  • 15
  • 75
  • 102
0

The include order needs to be switched in the master change log file. The company table isn't created by the time the db.changelog.stock.xml file is executed.

Christian Maslen
  • 1,100
  • 9
  • 13