diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java b/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java index 07ac9ad30..d0033f443 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java @@ -261,6 +261,13 @@ public class MColumn { return !draftOnly && !historyExclude; } + public void clearForeignKey() { + this.references = null; + this.foreignKeyName = null; + this.fkeyOnDelete = null; + this.fkeyOnUpdate = null; + } + public Column createColumn() { Column c = new Column(); diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index 62eafd3e3..df803382b 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -273,8 +273,7 @@ public class MTable { } for (MCompoundUniqueConstraint constraint : uniqueConstraints) { - UniqueConstraint uq = constraint.getUniqueConstraint(); - createTable.getUniqueConstraint().add(uq); + createTable.getUniqueConstraint().add(constraint.getUniqueConstraint()); } return createTable; @@ -789,4 +788,20 @@ public class MTable { public void setPartitionMeta(PartitionMeta partitionMeta) { this.partitionMeta = partitionMeta; } + + /** + * Clear foreign key as this element collection table logically references + * back to multiple tables. + */ + public MIndex setReusedElementCollection() { + MIndex index = null; + for (MColumn column : columns.values()) { + final String references = column.getReferences(); + if (references != null) { + index = new MIndex(column.getForeignKeyIndex(), name, column.getName()); + column.clearForeignKey(); + } + } + return index; + } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java index 7f0e50fa1..898fe8584 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java @@ -312,11 +312,29 @@ public class ModelContainer { return tables.put(table.getName(), table); } + /** + * Add an element table taking into account if it is reused/references back + * to multiple bean types (and so can't have foreign key). + */ + public void addTableElementCollection(MTable table) { + final MTable reusedElementCollection = tables.get(table.getName()); + if (reusedElementCollection != null) { + final MIndex index = reusedElementCollection.setReusedElementCollection(); + if (index != null) { + indexes.put(index.getIndexName(), index); + } + } else { + if (table.isPartitioned()) { + partitionedTables.add(table); + } + tables.put(table.getName(), table); + } + } + /** * Add a single column index. */ public void addIndex(String indexName, String tableName, String columnName) { - indexes.put(indexName, new MIndex(indexName, tableName, columnName)); } @@ -324,7 +342,6 @@ public class ModelContainer { * Add a multi column index. */ public void addIndex(String indexName, String tableName, String[] columnNames) { - indexes.put(indexName, new MIndex(indexName, tableName, columnNames)); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java index 9fc213faa..7a0b81bfd 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java @@ -95,6 +95,10 @@ public class ModelBuildContext { return model.addTable(table); } + public void addTableElementCollection(MTable table) { + model.addTableElementCollection(table); + } + public void addIndex(String indexName, String tableName, String columnName) { model.addIndex(indexName, tableName, columnName); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java index 0cbf2f2a4..744250e5f 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java @@ -17,15 +17,11 @@ public class ModelBuildElementTable { public static void build(ModelBuildContext ctx, BeanPropertyAssocMany manyProp) { BeanTable beanTable = manyProp.getBeanTable(); - BeanDescriptor targetDescriptor = manyProp.getTargetDescriptor(); - MTable table = new MTable(beanTable.getBaseTable()); VisitAllUsing.visitOne(targetDescriptor, new ModelBuildPropertyVisitor(ctx, table, targetDescriptor)); - - ctx.addTable(table); + ctx.addTableElementCollection(table); } - } diff --git a/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java b/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java index f02ecede7..e702964b1 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java @@ -15,6 +15,51 @@ import static org.assertj.core.api.Assertions.assertThat; public class ModelContainerTest { + @Test + public void elementCollectionTable_single_expect_foreignKeys() { + + ModelContainer container = new ModelContainer(); + + container.addTableElementCollection(createElementCollectionTable("ec_bean.id", "fk_ec_bean_ec_table")); + + final MTable ecTable = container.getTable("ec_table"); + final MColumn fkCol = ecTable.getColumn("fk_col"); + assertThat(fkCol.getReferences()).isEqualTo("ec_bean.id"); + } + + @Test + public void elementCollectionTable_reused_expect_noForeignKeys() { + + ModelContainer container = new ModelContainer(); + + container.addTableElementCollection(createElementCollectionTable("ec_bean.id", "fk_ec_bean_ec_table")); + container.addTableElementCollection(createElementCollectionTable("ec_otherBean.id", "fk_ec_otherBean_ec_table")); + + final MTable ecTable = container.getTable("ec_table"); + final MColumn fkCol = ecTable.getColumn("fk_col"); + assertThat(fkCol.getReferences()).isNull(); + assertThat(fkCol.getForeignKeyName()).isNull(); + + final MIndex index = container.getIndex("ix_ec_table"); + assertThat(index.getTableName()).isEqualTo("ec_table"); + assertThat(index.getColumns()).containsOnly("fk_col"); + } + + private MTable createElementCollectionTable(String references, String fkName) { + + MTable ecTable = new MTable("ec_table"); + final MColumn colFk = new MColumn("fk_col", "varchar", true); + colFk.setReferences(references); + colFk.setForeignKeyName(fkName); + colFk.setForeignKeyIndex("ix_ec_table"); + + ecTable.addColumn(colFk); + ecTable.addColumn(new MColumn("key", "varchar", true)); + ecTable.addColumn(new MColumn("val", "varchar", true)); + + return ecTable; + } + @Test public void apply_when_noPendingDrops_then_emptyPending() { diff --git a/src/test/java/org/tests/model/elementcollection/EcsmOne.java b/src/test/java/org/tests/model/elementcollection/EcsmOne.java new file mode 100644 index 000000000..58f3ec21b --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcsmOne.java @@ -0,0 +1,68 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Version; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +@Entity +public class EcsmOne { + + @Id + UUID oneId; + + String name; + + @ElementCollection + @CollectionTable(name = "ecsm_values", joinColumns = @JoinColumn(name = "host_id", referencedColumnName = "one_id")) + Set values = new LinkedHashSet<>(); + + @Version + long version; + + public EcsmOne(String name) { + this.name = name; + } + + @Override + public String toString() { + return "id:" + oneId + " name:" + name + " values:" + values; + } + + public UUID getOneId() { + return oneId; + } + + public void setOneId(UUID oneId) { + this.oneId = oneId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Set getValues() { + return values; + } + + public void setValues(Set values) { + this.values = values; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/EcsmTwo.java b/src/test/java/org/tests/model/elementcollection/EcsmTwo.java new file mode 100644 index 000000000..084a8f1a7 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcsmTwo.java @@ -0,0 +1,68 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Version; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +@Entity +public class EcsmTwo { + + @Id + UUID id; + + String name; + + @ElementCollection + @CollectionTable(name = "ecsm_values", joinColumns = @JoinColumn(name = "host_id", referencedColumnName = "id")) + Set values = new LinkedHashSet<>(); + + @Version + long version; + + public EcsmTwo(String name) { + this.name = name; + } + + @Override + public String toString() { + return "id:" + id + " name:" + name + " values:" + values; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Set getValues() { + return values; + } + + public void setValues(Set values) { + this.values = values; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionResused.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionResused.java new file mode 100644 index 000000000..d95b2549e --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionResused.java @@ -0,0 +1,36 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionResused extends BaseTestCase { + + @Test + public void insert_find_delete() { + + EcsmOne one = new EcsmOne("One028"); + one.getValues().add("128-1"); + one.getValues().add("128-2"); + + EcsmTwo two = new EcsmTwo("Two028"); + two.getValues().add("228-1"); + two.getValues().add("228-2"); + + DB.save(one); + DB.save(two); + + final EcsmOne foundOne = DB.find(EcsmOne.class, one.getOneId()); + assertThat(foundOne.getName()).isEqualTo("One028"); + assertThat(foundOne.getValues()).contains("128-1", "128-2"); + + final EcsmTwo foundTwo = DB.find(EcsmTwo.class, two.getId()); + assertThat(foundTwo.getName()).isEqualTo("Two028"); + assertThat(foundTwo.getValues()).contains("228-1", "228-2"); + + DB.delete(foundOne); + DB.delete(foundTwo); + } +}