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
Advertisement
Answer
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: