#435 - Duplicate foreign key name with ManyToMany relations

This commit is contained in:
Robin Bygrave
2015-10-29 17:44:29 +13:00
parent 8ca12521d7
commit ec1a68a133
5 changed files with 150 additions and 1 deletions
@@ -14,7 +14,7 @@ import java.util.List;
*/
public class MCompoundForeignKey {
private final String name;
private String name;
private final String referenceTable;
private final List<String> columns = new ArrayList<String>();
private final List<String> referenceColumns = new ArrayList<String>();
@@ -47,6 +47,28 @@ public class MCompoundForeignKey {
return fk;
}
/**
* Add a counter to the foreign key and index names to avoid duplication.
*/
public void addNameSuffix(int counter) {
this.name = name + "_" + counter;
this.indexName = indexName + "_" + counter;
}
/**
* Return the foreign key name.
*/
public String getName() {
return name;
}
/**
* Return the index name.
*/
public String getIndexName() {
return indexName;
}
/**
* Return the columns making up the foreign key in order.
*/
@@ -14,6 +14,7 @@ import com.avaje.ebean.dbmigration.migration.UniqueConstraint;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -482,4 +483,32 @@ public class MTable {
return (value == 0) ? null : BigInteger.valueOf(value);
}
/**
* Check if there are duplicate foreign keys.
* <p>
* This can occur when an ManyToMany relates back to itself.
* </p>
*/
public void checkDuplicateForeignKeys() {
if (hasDuplicateForeignKeys()) {
int counter = 1;
for (MCompoundForeignKey fk : compoundKeys) {
fk.addNameSuffix(counter++);
}
}
}
/**
* Return true if the foreign key names are not unique.
*/
private boolean hasDuplicateForeignKeys() {
Set<String> fkNames = new HashSet<String>();
for (MCompoundForeignKey fk : compoundKeys) {
if (!fkNames.add(fk.getName())) {
return true;
}
}
return false;
}
}
@@ -47,6 +47,8 @@ public class ModelBuildIntersectionTable {
BeanDescriptor<?> targetDesc = manyProp.getTargetDescriptor();
buildFkConstraints(targetDesc, tableJoin.columns(), false);
intersectionTable.checkDuplicateForeignKeys();
}
@@ -0,0 +1,29 @@
package com.avaje.tests.m2m;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.m2m.MnyTopic;
import org.junit.Test;
/**
* Added to test DDL generation for ManyToMany related back to itself.
*/
public class TestM2MSelfRelationship extends BaseTestCase {
@Test
public void test() {
Ebean.getDefaultServer();
// Create 2 roles r0 and r1
MnyTopic r0 = new MnyTopic("r0");
MnyTopic r1 = new MnyTopic("r1");
// Save r1 and r2
Ebean.save(r0);
Ebean.save(r1);
r0.getSubTopics().add(r1);
Ebean.save(r0);
}
}
@@ -0,0 +1,67 @@
package com.avaje.tests.model.m2m;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Version;
import java.util.List;
@Entity
public class MnyTopic {
@Id
Long id;
String name;
@Version
Long version;
@ManyToMany
@JoinTable(name = "subtopics",
joinColumns = @JoinColumn(name = "topic", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "subtopic", referencedColumnName = "id"))
List<MnyTopic> subTopics;
public MnyTopic() {
}
public MnyTopic(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long 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 List<MnyTopic> getSubTopics() {
return subTopics;
}
public void setSubTopics(List<MnyTopic> subTopics) {
this.subTopics = subTopics;
}
}