Skip to content

Commit 6c758c4

Browse files
committed
For Shared primary key usecase, adding logic to reuse the embeddedID class of parent table in Child table.
1 parent 0108d3d commit 6c758c4

File tree

4 files changed

+52
-56
lines changed

4 files changed

+52
-56
lines changed

src/main/java/io/github/ngbsn/generator/associations/OneToManyMappingsGenerator.java

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
import io.github.ngbsn.model.Table;
88
import io.github.ngbsn.model.annotations.field.*;
99
import io.github.ngbsn.util.Util;
10-
import org.apache.commons.text.WordUtils;
1110

1211
import java.util.ArrayList;
1312
import java.util.HashSet;
1413
import java.util.List;
1514
import java.util.Optional;
16-
import java.util.stream.Collectors;
1715
import java.util.stream.Stream;
1816

1917
/**
@@ -111,12 +109,19 @@ private static void handleSingleForeignKey(final Table table, final ForeignKeyCo
111109
private static void handleCompositeForeignKey(final Table table, final Table parentTable, final ForeignKeyConstraint foreignKeyConstraint,
112110
final Column parentTableField, final EmbeddableClass embeddableId, final List<Column> allPrimaryKeyColumns) {
113111
List<Column> listOfForeignKeyColumns = listOfForeignKeys(table, foreignKeyConstraint);
114-
//Case: Shared Composite Primary Key
115-
//If composite foreign key is inside the composite primary key, don't remove them from table.
116-
//This case assumes there is a primary composite key
117-
//Add a @MapsId annotation to the referenced table field
118-
if (embeddableId != null && new HashSet<>(allPrimaryKeyColumns).containsAll(listOfForeignKeyColumns)) {
119-
handleCompositeForeignKeyInsideCompositePrimaryKey(table, parentTable, parentTableField, embeddableId, listOfForeignKeyColumns);
112+
if(embeddableId != null && new HashSet<>(allPrimaryKeyColumns).equals(new HashSet<>(listOfForeignKeyColumns))){
113+
//Case: Shared Composite Primary Key
114+
//This case assumes there is a primary composite key
115+
//If composite foreign key has same columns as composite primary key, don't remove them from table.
116+
//Add a @MapsId annotation to the referenced table field
117+
handleCompositeForeignKeySameAsCompositePrimaryKey(table, parentTable, parentTableField);
118+
}
119+
else if (embeddableId != null && new HashSet<>(allPrimaryKeyColumns).containsAll(listOfForeignKeyColumns)) {
120+
//Case: Shared Composite Primary Key
121+
//This case assumes there is a primary composite key
122+
//If composite foreign key is inside the composite primary key, don't remove them from table.
123+
//Add a @MapsId annotation to the referenced table field
124+
handleCompositeForeignKeyInsideCompositePrimaryKey(parentTable, parentTableField, embeddableId, listOfForeignKeyColumns);
120125
} else {
121126
//Case1: There is no Composite primary key
122127
//TODO can part of Composite foreign key be a primary key. Is this applicable only to self referencing cases?
@@ -136,38 +141,40 @@ private static void handleCompositeForeignKey(final Table table, final Table par
136141
parentTableField.getAnnotations().add(JoinColumnsAnnotation.builder().joinColumns(joinColumns).build().toString());
137142
}
138143

139-
private static void handleCompositeForeignKeyInsideCompositePrimaryKey(final Table table, final Table parentTable, final Column parentTableField,
144+
private static void handleCompositeForeignKeySameAsCompositePrimaryKey(final Table table, final Table parentTable, final Column parentTableField) {
145+
//Reuse the parent table embeddedId class to create a field for the shared primary key
146+
EmbeddableClass parentEmbeddedId = parentTable.getEmbeddedId();
147+
Column parentEmbeddedIdColumn = new Column();
148+
parentEmbeddedIdColumn.setType(parentTable.getClassName() + "." + parentEmbeddedId.getClassName());
149+
parentEmbeddedIdColumn.setFieldName(parentEmbeddedId.getFieldName());
150+
parentEmbeddedIdColumn.setEmbeddedId(true);
151+
table.getColumns().add(parentEmbeddedIdColumn);
152+
//Remove EmbeddedID from child table
153+
table.setEmbeddedId(null);
154+
155+
//Add @MapsId annotation, as the shared primary key is not set explicitly in this table, rather managed through parent primary key
156+
parentTableField.getAnnotations().add(MapsIdAnnotation.builder().fieldName(parentEmbeddedIdColumn.getFieldName()).build().toString());
157+
}
158+
159+
private static void handleCompositeForeignKeyInsideCompositePrimaryKey(final Table parentTable, final Column parentTableField,
140160
final EmbeddableClass embeddableId, final List<Column> listOfForeignKeyColumns) {
161+
//remove all foreign key columns as they are tracked by the EmbeddedID field of parent
162+
listOfForeignKeyColumns.forEach(column ->
163+
embeddableId.getColumns().remove(column)
164+
);
165+
166+
//Reuse the parent table embeddedId class to create a field for the shared primary key
167+
EmbeddableClass parentEmbeddedId = parentTable.getEmbeddedId();
168+
Column parentEmbeddedIdColumn = new Column();
169+
parentEmbeddedIdColumn.setType(parentTable.getClassName() + "." + parentEmbeddedId.getClassName());
170+
parentEmbeddedIdColumn.setFieldName(parentEmbeddedId.getFieldName());
171+
embeddableId.getColumns().add(parentEmbeddedIdColumn);
141172

142-
EmbeddableClass foreignCompositeKeyEmbedded = new EmbeddableClass(); //Create a new embeddable for this foreign composite key
143-
String embeddableName = listOfForeignKeyColumns.stream().map(Column::getFieldName).collect(Collectors.joining());
144-
foreignCompositeKeyEmbedded.setClassName(WordUtils.capitalize(embeddableName));
145-
foreignCompositeKeyEmbedded.setFieldName(embeddableName);
146-
table.getEmbeddableClasses().add(foreignCompositeKeyEmbedded); //add new embeddable to the Table list of Embeddables
147-
listOfForeignKeyColumns.forEach(column -> {
148-
//Remove existing column annotations and add again with updatable=false, insertable=false.
149-
//This is necessary as the column is inserted/updated through foreign key
150-
column.getAnnotations().removeIf(s -> s.contains("@Column"));
151-
column.getAnnotations().add(ColumnAnnotation.builder()
152-
.columnName(column.getColumnName())
153-
.updatable(false)
154-
.insertable(false)
155-
.build().toString());
156-
157-
//add the individual foreign keys columns to the newly created embeddable
158-
foreignCompositeKeyEmbedded.getColumns().add(column);
159-
//Remove the individual foreign keys from EmbeddedId and add the newly created embeddable into EmbeddedId
160-
embeddableId.getColumns().remove(column);
161-
});
162-
Column foreignCompositeField = new Column();
163-
foreignCompositeField.setType(foreignCompositeKeyEmbedded.getClassName());
164-
foreignCompositeField.setFieldName(foreignCompositeKeyEmbedded.getFieldName());
165-
embeddableId.getColumns().add(foreignCompositeField);
166-
167-
if (embeddableId.getFieldName() != null)
168-
parentTableField.getAnnotations().add(MapsIdAnnotation.builder().fieldName(foreignCompositeField.getFieldName()).build().toString());
173+
//Add @MapsId annotation, as the shared primary key is not set explicitly in this table, rather managed through parent primary key
174+
parentTableField.getAnnotations().add(MapsIdAnnotation.builder().fieldName(parentEmbeddedIdColumn.getFieldName()).build().toString());
169175
}
170176

177+
171178
/**
172179
* Convert column names in foreignKeyConstraint to List of Column models
173180
* @param table table

src/main/java/io/github/ngbsn/model/Column.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ public class Column {
1515
private String type;
1616
private boolean primaryKey;
1717
private boolean sharedPrimaryKey;
18+
private boolean embeddedId;
1819
private List<String> annotations = new ArrayList<>();
1920
}

src/main/java/io/github/ngbsn/model/Table.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ public class Table {
1717
private List<String> annotations = new ArrayList<>();
1818
private int numOfPrimaryKeyColumns;
1919
private List<ForeignKeyConstraint> foreignKeyConstraints = new ArrayList<>();
20-
private List<EmbeddableClass> embeddableClasses = new ArrayList<>();
2120
private EmbeddableClass embeddedId;
2221
private List<TableEnum> tableEnums = new ArrayList<>();
2322
}

src/main/resources/templates/entity.ftl

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,8 @@ public class ${table.className}{
2828
}
2929
</#list>
3030

31+
<#-- Case: Composite Primary Key -->
3132
<#if (table.numOfPrimaryKeyColumns > 1) >
32-
<#list table.embeddableClasses as embeddableClass>
33-
@NoArgsConstructor
34-
@AllArgsConstructor
35-
@Getter
36-
@Setter
37-
@Builder
38-
@Embeddable
39-
public static class ${embeddableClass.className} implements Serializable{
40-
<#list embeddableClass.columns as column>
41-
<#list column.annotations as annotation>
42-
${annotation}
43-
</#list>
44-
private ${column.type} ${column.fieldName};
45-
46-
</#list>
47-
}
48-
</#list>
49-
5033
<#if table.embeddedId??>
5134
@NoArgsConstructor
5235
@AllArgsConstructor
@@ -68,18 +51,24 @@ public class ${table.className}{
6851
</#if>
6952

7053
<#list table.columns as column>
71-
<#if column.primaryKey == false>
54+
<#if column.primaryKey == false && column.embeddedId == false>
7255
<#list column.annotations as annotation>
7356
${annotation}
7457
</#list>
7558
private ${column.type} ${column.fieldName};
7659
</#if>
60+
<#-- This is for shared primary key usecase -->
61+
<#if column.embeddedId == true>
62+
@EmbeddedId
63+
private ${column.type} ${column.fieldName};
64+
</#if>
7765

7866
</#list>
7967
<#else>
8068
<#list table.columns as column>
8169
<#if column.primaryKey == true>
8270
@Id
71+
<#-- If foreign key is primary key, then no need for ID generation in this table, its handled by referenced table -->
8372
<#if column.sharedPrimaryKey == false && (column.type == "Integer" || column.type == "Short" || column.type == "Long") >
8473
@GeneratedValue(strategy = GenerationType.IDENTITY)
8574
</#if>

0 commit comments

Comments
 (0)