From c13735ee610514a2a44a8baf8dcea9c644f5c7b6 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:51:07 +0100 Subject: [PATCH 01/14] update test dataMaps --- .../src/test/resources/lifecycle-map.map.xml | 8 ++-- .../src/test/resources/compound.map.xml | 8 ++-- .../src/test/resources/embeddable.map.xml | 4 +- .../src/test/resources/generated.map.xml | 8 ++-- .../inheritance-single-table1.map.xml | 8 ++-- .../resources/inheritance-vertical.map.xml | 40 +++++++++---------- .../src/test/resources/meaningful-pk.map.xml | 4 +- .../src/test/resources/multi-tier.map.xml | 4 +- .../configuration/xml/testConfigMap4.map.xml | 12 +++--- .../relationships-delete-rules.map.xml | 8 ++-- .../resources/relationships-flattened.map.xml | 8 ++-- .../relationships-many-to-many-join.map.xml | 8 ++-- .../relationships-to-many-fk.map.xml | 4 +- .../src/test/resources/testmap.map.xml | 24 +++++------ .../src/test/resources/toone.map.xml | 4 +- .../unsupported-distinct-types.map.xml | 16 ++++---- 16 files changed, 84 insertions(+), 84 deletions(-) diff --git a/cayenne-commitlog/src/test/resources/lifecycle-map.map.xml b/cayenne-commitlog/src/test/resources/lifecycle-map.map.xml index cbcba1c2f7..fbd8f002b9 100644 --- a/cayenne-commitlog/src/test/resources/lifecycle-map.map.xml +++ b/cayenne-commitlog/src/test/resources/lifecycle-map.map.xml @@ -116,16 +116,16 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/compound.map.xml b/cayenne-server/src/test/resources/compound.map.xml index 2570294293..3ad42f04e6 100644 --- a/cayenne-server/src/test/resources/compound.map.xml +++ b/cayenne-server/src/test/resources/compound.map.xml @@ -86,17 +86,17 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/embeddable.map.xml b/cayenne-server/src/test/resources/embeddable.map.xml index e65c5eb889..7b39c29658 100644 --- a/cayenne-server/src/test/resources/embeddable.map.xml +++ b/cayenne-server/src/test/resources/embeddable.map.xml @@ -56,7 +56,7 @@ - + @@ -65,7 +65,7 @@ - + diff --git a/cayenne-server/src/test/resources/generated.map.xml b/cayenne-server/src/test/resources/generated.map.xml index 38a9c79500..2c5c530183 100644 --- a/cayenne-server/src/test/resources/generated.map.xml +++ b/cayenne-server/src/test/resources/generated.map.xml @@ -63,16 +63,16 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/inheritance-single-table1.map.xml b/cayenne-server/src/test/resources/inheritance-single-table1.map.xml index 11f798b80f..ffa9a282a1 100644 --- a/cayenne-server/src/test/resources/inheritance-single-table1.map.xml +++ b/cayenne-server/src/test/resources/inheritance-single-table1.map.xml @@ -53,22 +53,22 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/inheritance-vertical.map.xml b/cayenne-server/src/test/resources/inheritance-vertical.map.xml index 4cf9f46e97..664f0ace46 100644 --- a/cayenne-server/src/test/resources/inheritance-vertical.map.xml +++ b/cayenne-server/src/test/resources/inheritance-vertical.map.xml @@ -170,16 +170,16 @@ - + - + - + - + @@ -191,28 +191,28 @@ - + - + - + - + - + - + - + @@ -221,7 +221,7 @@ - + @@ -236,28 +236,28 @@ - + - + - + - + - + - + - + - + diff --git a/cayenne-server/src/test/resources/meaningful-pk.map.xml b/cayenne-server/src/test/resources/meaningful-pk.map.xml index c72e416567..d8105e1171 100644 --- a/cayenne-server/src/test/resources/meaningful-pk.map.xml +++ b/cayenne-server/src/test/resources/meaningful-pk.map.xml @@ -49,13 +49,13 @@ - + - + diff --git a/cayenne-server/src/test/resources/multi-tier.map.xml b/cayenne-server/src/test/resources/multi-tier.map.xml index 7c45cfe266..566366fdad 100644 --- a/cayenne-server/src/test/resources/multi-tier.map.xml +++ b/cayenne-server/src/test/resources/multi-tier.map.xml @@ -54,7 +54,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/testConfigMap4.map.xml b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/testConfigMap4.map.xml index 9513b1cb00..81a7a44fd7 100644 --- a/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/testConfigMap4.map.xml +++ b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/testConfigMap4.map.xml @@ -177,7 +177,7 @@ - + @@ -186,10 +186,10 @@ - + - + @@ -198,7 +198,7 @@ - + @@ -216,13 +216,13 @@ - + - + diff --git a/cayenne-server/src/test/resources/relationships-delete-rules.map.xml b/cayenne-server/src/test/resources/relationships-delete-rules.map.xml index c2553352aa..cf337af20d 100644 --- a/cayenne-server/src/test/resources/relationships-delete-rules.map.xml +++ b/cayenne-server/src/test/resources/relationships-delete-rules.map.xml @@ -30,16 +30,16 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/relationships-flattened.map.xml b/cayenne-server/src/test/resources/relationships-flattened.map.xml index e1f3938cfd..0d54de020a 100644 --- a/cayenne-server/src/test/resources/relationships-flattened.map.xml +++ b/cayenne-server/src/test/resources/relationships-flattened.map.xml @@ -99,16 +99,16 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml b/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml index 4da95b3346..9f73c7ec29 100644 --- a/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml +++ b/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml @@ -22,16 +22,16 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/relationships-to-many-fk.map.xml b/cayenne-server/src/test/resources/relationships-to-many-fk.map.xml index 149b044f4b..4e3d8e468e 100644 --- a/cayenne-server/src/test/resources/relationships-to-many-fk.map.xml +++ b/cayenne-server/src/test/resources/relationships-to-many-fk.map.xml @@ -32,13 +32,13 @@ - + - + diff --git a/cayenne-server/src/test/resources/testmap.map.xml b/cayenne-server/src/test/resources/testmap.map.xml index 0b2ee630c0..06520b3893 100644 --- a/cayenne-server/src/test/resources/testmap.map.xml +++ b/cayenne-server/src/test/resources/testmap.map.xml @@ -164,7 +164,7 @@ - + @@ -176,31 +176,31 @@ - + - + - + - + - + - + - + @@ -212,19 +212,19 @@ - + - + - + - + diff --git a/cayenne-server/src/test/resources/toone.map.xml b/cayenne-server/src/test/resources/toone.map.xml index ef9ddbfaa4..d2d78c9b8b 100644 --- a/cayenne-server/src/test/resources/toone.map.xml +++ b/cayenne-server/src/test/resources/toone.map.xml @@ -12,10 +12,10 @@ - + - + diff --git a/cayenne-server/src/test/resources/unsupported-distinct-types.map.xml b/cayenne-server/src/test/resources/unsupported-distinct-types.map.xml index 3c6d7ea12b..578df54629 100644 --- a/cayenne-server/src/test/resources/unsupported-distinct-types.map.xml +++ b/cayenne-server/src/test/resources/unsupported-distinct-types.map.xml @@ -26,28 +26,28 @@ - + - + - + - + - + - + - + - + From 04532a65842886eef1845868cc334ddaad4e6373 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:55:47 +0100 Subject: [PATCH 02/14] update tests --- .../dbsync/merge/DataMapMergerTest.java | 20 +++++++++---------- .../cayenne/dbsync/merge/MergerFactoryIT.java | 2 ++ .../dbsync/merge/builders/DataMapBuilder.java | 8 ++++---- .../merge/builders/DbRelationshipBuilder.java | 16 +++++++++++++-- .../token/model/DropColumnToModelIT.java | 1 + .../model/DropRelationshipToModelIT.java | 1 + .../reverse/dbload/RelationshipsLoaderIT.java | 2 +- .../flush/ArcValuesCreationHandlerTest.java | 12 +++++------ .../xml/DbRelationshipHandlerTest.java | 2 +- 9 files changed, 40 insertions(+), 24 deletions(-) diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/DataMapMergerTest.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/DataMapMergerTest.java index 4f14d81433..33c2301520 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/DataMapMergerTest.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/DataMapMergerTest.java @@ -252,7 +252,7 @@ public void testAddRelationship() throws Exception { dbEntity("table2").attributes( dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt()) - ).join("rel", "table1.attr01", "table2.attr01") + ).join("rel", "table1.attr01", "table2.attr01", true) .build(); DataMap db = dataMap().with( @@ -287,8 +287,8 @@ public void testAddRelationship1() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "table1.attr01", "table2.attr01") - .join("rel1", "table1.attr01", "table2.attr03") + ).join("rel", "table1.attr01", "table2.attr01",true) + .join("rel1", "table1.attr01", "table2.attr03",false) .build(); DataMap db = dataMap().with( @@ -300,8 +300,8 @@ public void testAddRelationship1() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "table1.attr01", "table2.attr02") - .join("rel1", "table1.attr01", "table2.attr03") + ).join("rel", "table1.attr01", "table2.attr02",true) + .join("rel1", "table1.attr01", "table2.attr03",false) .build(); @@ -329,7 +329,7 @@ public void testTableNameUppercaseRelationship() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "TABLE1.attr01", "table2.attr01").build(); + ).join("rel", "TABLE1.attr01", "table2.attr01",true).build(); DataMap db = dataMap().with( dbEntity("table1").attributes( @@ -340,7 +340,7 @@ public void testTableNameUppercaseRelationship() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "table1.attr01", "table2.attr01").build(); + ).join("rel", "table1.attr01", "table2.attr01",false).build(); List tokens = dbMerger().createMergeTokens(existing, db); @@ -358,7 +358,7 @@ public void testAttributeNameUppercaseRelationship() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "table1.ATTR01", "table2.attr01").build(); + ).join("rel", "table1.ATTR01", "table2.attr01",true).build(); DataMap db = dataMap().with( dbEntity("table1").attributes( @@ -369,7 +369,7 @@ public void testAttributeNameUppercaseRelationship() throws Exception { dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt().primaryKey(), dbAttr("attr03").typeInt().primaryKey()) - ).join("rel", "table1.attr01", "table2.attr01").build(); + ).join("rel", "table1.attr01", "table2.attr01",false).build(); List tokens = dbMerger().createMergeTokens(existing, db); @@ -397,7 +397,7 @@ public void testRemoveRelationship() throws Exception { dbEntity("table2").attributes( dbAttr("attr01").typeInt().primaryKey(), dbAttr("attr02").typeInt()) - ).join("rel", "table1.attr01", "table2.attr01") + ).join("rel", "table1.attr01", "table2.attr01",true) .build(); diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergerFactoryIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergerFactoryIT.java index 4d420d41a2..900bd996ca 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergerFactoryIT.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/MergerFactoryIT.java @@ -201,6 +201,7 @@ public void testAddForeignKeyWithTable() throws Exception { r1.setSourceEntity(dbEntity); r1.setTargetEntityName(artistDbEntity); r1.setToMany(false); + r1.setFK(true); r1.addJoin(new DbJoin(r1, "ARTIST_ID", "ARTIST_ID")); dbEntity.addRelationship(r1); @@ -262,6 +263,7 @@ public void testAddForeignKeyAfterTable() throws Exception { r1.setSourceEntity(dbEntity); r1.setTargetEntityName(artistDbEntity); r1.setToMany(false); + r1.setFK(true); r1.addJoin(new DbJoin(r1, "ARTIST_ID", "ARTIST_ID")); dbEntity.addRelationship(r1); diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DataMapBuilder.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DataMapBuilder.java index 5a7d518aaf..e89cc46558 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DataMapBuilder.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DataMapBuilder.java @@ -87,11 +87,11 @@ public DataMapBuilder withObjEntities(int count) { return this; } - public DataMapBuilder join(String from, String to) { - return join(null, from, to); + public DataMapBuilder join(String from, String to,boolean isFK) { + return join(null, from, to,isFK); } - public DataMapBuilder join(String name, String from, String to) { + public DataMapBuilder join(String name, String from, String to, boolean isFK) { String[] fromSplit = from.split("\\."); DbEntity fromEntity = obj.getDbEntity(fromSplit[0]); if (fromEntity == null) { @@ -103,7 +103,7 @@ public DataMapBuilder join(String name, String from, String to) { fromEntity.addRelationship(new DbRelationshipBuilder(name) .from(fromEntity, fromSplit[1]) .to(toSplit[0], toSplit[1]) - + .fK(isFK) .build()); return this; diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DbRelationshipBuilder.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DbRelationshipBuilder.java index d9d8553e2e..5543280497 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DbRelationshipBuilder.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/builders/DbRelationshipBuilder.java @@ -52,14 +52,19 @@ public DbRelationshipBuilder name(String name) { return this; } - public DbRelationshipBuilder from(DbEntity entity, String ... columns) { + public DbRelationshipBuilder from(DbEntity entity, String... columns) { obj.setSourceEntity(entity); this.from = columns; return this; } - public DbRelationshipBuilder to(String entityName, String ... columns) { + public DbRelationshipBuilder fK(boolean fk) { + obj.setFK(fk); + return this; + } + + public DbRelationshipBuilder to(String entityName, String... columns) { obj.setTargetEntityName(entityName); this.to = columns; @@ -80,6 +85,13 @@ public DbRelationship build() { obj.addJoin(new DbJoin(obj, from[i], to[i])); } + DbJoin join = new DbJoin(obj); + if (!obj.isFK() && join.getTarget() != null && join.getSource() != null) { + if (join.getTarget().isPrimaryKey() && !join.getSource().isPrimaryKey()) { + obj.setFK(true); + } + } + return obj; } } diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropColumnToModelIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropColumnToModelIT.java index 69e5cc3163..360ef4e8a2 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropColumnToModelIT.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropColumnToModelIT.java @@ -151,6 +151,7 @@ public void testRemoveFKColumnWithoutRelationshipInDb() throws Exception { rel2To1.setSourceEntity(dbEntity2); rel2To1.setTargetEntityName(dbEntity1); rel2To1.setToMany(false); + rel2To1.setFK(true); rel2To1.addJoin(new DbJoin(rel2To1, e2col2.getName(), e1col1.getName())); dbEntity2.addRelationship(rel2To1); assertSame(rel1To2, rel2To1.getReverseRelationship()); diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropRelationshipToModelIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropRelationshipToModelIT.java index 7dc4d5a965..73558ff9e4 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropRelationshipToModelIT.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/model/DropRelationshipToModelIT.java @@ -86,6 +86,7 @@ public void testForeignKey() throws Exception { rel2To1.setSourceEntity(dbEntity2); rel2To1.setTargetEntityName(dbEntity1); rel2To1.setToMany(false); + rel2To1.setFK(true); rel2To1.addJoin(new DbJoin(rel2To1, e2col2.getName(), e1col1.getName())); dbEntity2.addRelationship(rel2To1); assertSame(rel1To2, rel2To1.getReverseRelationship()); diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java index 40b64cf4c2..2c0189a0eb 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java @@ -76,7 +76,7 @@ public void testRelationshipLoad() throws Exception { assertNotNull("No relationship to PAINTING_INFO", oneToOne); assertFalse("Relationship to PAINTING_INFO must be to-one", oneToOne.isToMany()); - assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isToDependentPK()); + assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isFK()); } // private void assertUniqueConstraintsInRelationships(DataMap map) { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/ArcValuesCreationHandlerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/ArcValuesCreationHandlerTest.java index b6ad2f7384..3acf82e859 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/ArcValuesCreationHandlerTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/ArcValuesCreationHandlerTest.java @@ -87,7 +87,7 @@ public void processRelationshipPkPkMaster() { ObjectId targetId = ObjectId.of("test2", "id2", 2); DbRelationship relationship = DbRelBuilder.of("id1", "id2") - .withToDepPk().withDstPk().withSrcPk().build(); + .withDstPk().withSrcPk().build(); handler.processRelationship(relationship, srcId, targetId, true); @@ -105,7 +105,7 @@ public void processRelationshipPkPkDependent() { ObjectId targetId = ObjectId.of("test2", "id2", 2); DbRelationship relationship = DbRelBuilder.of("id1", "id2") - .withDstPk().withSrcPk().build(); + .withFk().withDstPk().withSrcPk().build(); handler.processRelationship(relationship, srcId, targetId, true); @@ -164,7 +164,7 @@ final static class DbRelBuilder { private String dstName; private boolean srcPk; private boolean dstPk; - private boolean toDepPk; + private boolean fK; static DbRelBuilder of(String srcName, String dstName) { DbRelBuilder builder = new DbRelBuilder(); @@ -183,14 +183,14 @@ DbRelBuilder withDstPk() { return this; } - DbRelBuilder withToDepPk() { - toDepPk = true; + DbRelBuilder withFk() { + fK = true; return this; } DbRelationship build() { DbRelationship relationship = mock(DbRelationship.class); - when(relationship.isToDependentPK()).thenReturn(toDepPk); + when(relationship.isFK()).thenReturn(fK); DbJoin join = mock(DbJoin.class); DbAttribute src = new DbAttribute(srcName); src.setPrimaryKey(srcPk); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/DbRelationshipHandlerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/DbRelationshipHandlerTest.java index 98e41c5f97..209a716dc3 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/DbRelationshipHandlerTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/DbRelationshipHandlerTest.java @@ -50,7 +50,7 @@ public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandl assertNotNull(relationship); assertEquals("PAINTING", relationship.getTargetEntityName()); - assertTrue(relationship.isToDependentPK()); + assertTrue(!relationship.isFK()); assertTrue(relationship.isToMany()); assertEquals("ID", relationship.getJoins().get(0).getSourceName()); assertEquals("ARTIST_ID", relationship.getJoins().get(0).getTargetName()); From c459290ecac3cc293ed405558ddf9382bb9f7bb4 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:56:27 +0100 Subject: [PATCH 03/14] update xsd schema --- .../main/resources/org/apache/cayenne/schema/11/modelMap.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cayenne-server/src/main/resources/org/apache/cayenne/schema/11/modelMap.xsd b/cayenne-server/src/main/resources/org/apache/cayenne/schema/11/modelMap.xsd index 014f419f22..a388cad334 100644 --- a/cayenne-server/src/main/resources/org/apache/cayenne/schema/11/modelMap.xsd +++ b/cayenne-server/src/main/resources/org/apache/cayenne/schema/11/modelMap.xsd @@ -149,7 +149,7 @@ - + From 4500d89887f3b398ffc1202ff6c4c2dacdf6f861 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:01:52 +0100 Subject: [PATCH 04/14] reading/writing in xml --- .../cayenne/configuration/xml/DbRelationshipHandler.java | 7 ++++++- .../main/java/org/apache/cayenne/map/DbRelationship.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java index da390e1ddc..71cc0342b2 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/DbRelationshipHandler.java @@ -79,7 +79,7 @@ private void createRelationship(Attributes attributes) throws SAXException { dbRelationship.setSourceEntity(source); dbRelationship.setTargetEntityName(attributes.getValue("target")); dbRelationship.setToMany(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("toMany"))); - dbRelationship.setToDependentPK(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("toDependentPK"))); + dbRelationship.setFK(DataMapHandler.TRUE.equalsIgnoreCase(attributes.getValue("fk"))); source.addRelationship(dbRelationship); } @@ -89,6 +89,11 @@ private void createDbAttributePair(Attributes attributes) { join.setSourceName(attributes.getValue("source")); join.setTargetName(attributes.getValue("target")); dbRelationship.addJoin(join); + if (!dbRelationship.isFK() && join.getTarget() != null) { + if (join.getTarget().isPrimaryKey() && !join.getSource().isPrimaryKey()) { + dbRelationship.setFK(true); + } + } } public DbRelationship getDbRelationship() { diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java index 15145ca729..4fc2792e92 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java @@ -77,7 +77,7 @@ public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) { encoder.attribute("target", getTargetEntityName()); } - encoder.attribute("toDependentPK", isToDependentPK() && isValidForDepPk()); + encoder.attribute("fk", isFK() && isValidForDepPk()); encoder.attribute("toMany", isToMany()); encoder.nested(getJoins(), delegate); From 19490039ce32bd8e1b0bac18f9fbf7a11df69e1e Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:08:58 +0100 Subject: [PATCH 05/14] logic in cayenne-server --- .../apache/cayenne/access/DbGenerator.java | 4 +- .../flush/ArcValuesCreationHandler.java | 2 +- .../operation/GraphBasedDbRowOpSorter.java | 2 +- .../cayenne/ashwood/AshwoodEntitySorter.java | 2 +- .../java/org/apache/cayenne/map/DbEntity.java | 4 +- .../apache/cayenne/map/DbRelationship.java | 47 +++++-------------- .../apache/cayenne/map/ObjRelationship.java | 4 +- 7 files changed, 21 insertions(+), 44 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java index 022cc367b0..4a71a84de7 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java @@ -361,11 +361,11 @@ public List createConstraintsQueries(DbEntity table) { } // create an FK CONSTRAINT only if the relationship is to PK - // and if this is not a dependent PK + // and if this is FK // create UNIQUE CONSTRAINT on FK if reverse relationship is to-one - if (rel.isToPK() && !rel.isToDependentPK()) { + if (rel.isToPK() && rel.isFK()) { if (getAdapter().supportsUniqueConstraints()) { diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java index 91f86bd5d6..6abd47744c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java @@ -191,7 +191,7 @@ protected void processRelationship(DbRelationship dbRelationship, ObjectId srcId } else { // case 2 and 3 processDelete = false; - if(dbRelationship.isToDependentPK()) { + if(!dbRelationship.isFK()) { valueToUse = ObjectIdValueSupplier.getFor(srcId, join.getSourceName()); rowOp = factory.getOrCreate(dbRelationship.getTargetEntity(), targetId, DbRowOpType.UPDATE); attribute = join.getTarget(); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/GraphBasedDbRowOpSorter.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/GraphBasedDbRowOpSorter.java index 8ed9617736..e16afa5ecf 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/GraphBasedDbRowOpSorter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/GraphBasedDbRowOpSorter.java @@ -82,7 +82,7 @@ private void initDataNoSync() { resolver.getDbEntities().forEach(entity -> entity.getRelationships().forEach(dbRelationship -> { - if(dbRelationship.isToMany() || !dbRelationship.isToPK() || dbRelationship.isToDependentPK()) { + if(dbRelationship.isToMany() || !dbRelationship.isToPK() || !dbRelationship.isFK()) { // TODO: can we ignore all of these relationships? return; } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java b/cayenne-server/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java index 169ad91f27..6b3f118fd4 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/ashwood/AshwoodEntitySorter.java @@ -113,7 +113,7 @@ protected void doIndexSorter() { for (DbEntity destination : entityResolver.getDbEntities()) { for (DbRelationship candidate : destination.getRelationships()) { - if ((!candidate.isToMany() && !candidate.isToDependentPK()) || candidate.isToMasterPK()) { + if ( candidate.isToMasterPK()) { DbEntity origin = candidate.getTargetEntity(); boolean newReflexive = destination.equals(origin); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java index ef4305f150..67b984dd6c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java @@ -426,8 +426,8 @@ private void handleAttributeUpdate(AttributeEvent e) { // check toDep PK for reverse relationships for (DbRelationship rel : getRelationships()) { DbRelationship reverse = rel.getReverseRelationship(); - if(reverse != null && reverse.isToDependentPK() && !reverse.isValidForDepPk()) { - reverse.setToDependentPK(false); + if(reverse != null && reverse.isFK() && !reverse.isValidForFk()) { + reverse.setFK(false); } } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java index 4fc2792e92..fbacbb481f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java @@ -42,11 +42,7 @@ public class DbRelationship extends Relationship joins = new ArrayList<>(2); - // Is relationship from source to target points to dependent primary - // key (primary key column of destination table that is also a FK to the - // source - // column) - protected boolean toDependentPK; + protected boolean isFK; public DbRelationship() { super(); @@ -77,7 +73,7 @@ public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) { encoder.attribute("target", getTargetEntityName()); } - encoder.attribute("fk", isFK() && isValidForDepPk()); + encoder.attribute("fk", isFK() && isValidForFk()); encoder.attribute("toMany", isToMany()); encoder.nested(getJoins(), delegate); @@ -146,14 +142,7 @@ public DbRelationship createReverseRelationship() { DbRelationship reverse = new DbRelationship(); reverse.setSourceEntity(targetEntity); reverse.setTargetEntityName(getSourceEntity().getName()); - - // TODO: andrus 12/24/2007 - one more case to handle - set reverse - // toDepPK = true - // if this relationship toDepPK is false, but the entities are joined on - // a PK... - // on the other hand, these can still be two independent entities... - - if (isToDependentPK() && !toMany && joins.size() == targetEntity.getPrimaryKeys().size()) { + if (!isFK() && !toMany && joins.size() == targetEntity.getPrimaryKeys().size()) { reverse.setToMany(false); } else { reverse.setToMany(!toMany); @@ -258,16 +247,11 @@ public boolean isFromPK() { } /** - * Returns true if a method isToDependentPK of - * reverse relationship of this relationship returns true. + * Returns true if a method isFK of + * reverse relationship of this relationship returns false. */ public boolean isToMasterPK() { - if (isToMany() || isToDependentPK()) { - return false; - } - - DbRelationship revRel = getReverseRelationship(); - return revRel != null && revRel.isToDependentPK(); + return !isToMany() && isFK(); } /** @@ -278,28 +262,21 @@ public boolean isToMasterPK() { * @since 4.0 */ public boolean isSourceIndependentFromTargetChange() { - // note - call "isToPK" at the end of the chain, since - // if it is to a dependent PK, we still should return true... - return isToMany() || isToDependentPK() || !isToPK(); + return !isFK(); } - /** - * Returns true if relationship from source to target points to - * dependent primary key. Dependent PK is a primary key column of the - * destination table that is also a FK to the source column. - */ - public boolean isToDependentPK() { - return toDependentPK; + public boolean isFK() { + return isFK; } - public void setToDependentPK(boolean toDependentPK) { - this.toDependentPK = toDependentPK; + public void setFK(boolean FK) { + this.isFK = FK; } /** * @since 1.1 */ - public boolean isValidForDepPk() { + public boolean isValidForFk() { // handle case with no joins if (getJoins().size() == 0) { return false; diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java index ee36fbf68f..ba59bba256 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java @@ -321,7 +321,7 @@ public boolean isOptional() { return false; } DbRelationship reverseRelationship = dbRelationship.getReverseRelationship(); - return !reverseRelationship.isToDependentPK(); + return reverseRelationship.isFK(); } return true; @@ -378,7 +378,7 @@ public boolean isSourceIndependentFromTargetChange() { * Returns true if underlying DbRelationships point to dependent entity. */ public boolean isToDependentEntity() { - return (getDbRelationships().get(0)).isToDependentPK(); + return !(getDbRelationships().get(0)).isFK(); } /** From f76f28f8a6350d5294f4fc0668c5eb57a619cfcc Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:12:09 +0100 Subject: [PATCH 06/14] logic in cayenne-dbsync --- .../merge/factory/IngresMergerTokenFactory.java | 2 +- .../reverse/dbimport/ManyToManyCandidateEntity.java | 4 ++-- .../dbsync/reverse/dbload/RelationshipLoader.java | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/IngresMergerTokenFactory.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/IngresMergerTokenFactory.java index 74c929dabf..4f24435183 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/IngresMergerTokenFactory.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/IngresMergerTokenFactory.java @@ -80,7 +80,7 @@ public MergerToken createAddRelationshipToDb(DbEntity entity, final DbRelationsh return new AddRelationshipToDb(entity, rel) { @Override public List createSql(DbAdapter adapter) { - if (!rel.isToMany() && rel.isToPK() && !rel.isToDependentPK()) { + if (rel.isToMasterPK()) { DbEntity source = (DbEntity) rel.getSourceEntity(); QuotingStrategy context = adapter.getQuotingStrategy(); diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java index 3eb9836074..eed688d80f 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbimport/ManyToManyCandidateEntity.java @@ -87,8 +87,8 @@ private boolean isManyToMany() { boolean isNotHaveAttributes = joinEntity.getAttributes().size() == 0; return isNotHaveAttributes - && reverseRelationship1 != null && reverseRelationship1.isToDependentPK() - && reverseRelationship2 != null && reverseRelationship2.isToDependentPK() + && reverseRelationship1 != null && !reverseRelationship1.isFK() + && reverseRelationship2 != null && !reverseRelationship2.isFK() && entity1 != null && entity2 != null; } diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java index fdd2899b11..aa348c1c34 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java @@ -87,10 +87,10 @@ public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLExcep createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship); - boolean toDependentPK = isToDependentPK(forwardRelationship); - boolean toMany = isToMany(toDependentPK, fkEntity, forwardRelationship); + boolean fk = isFK(forwardRelationship); + boolean toMany = isToMany(fk, fkEntity, forwardRelationship); - forwardRelationship.setToDependentPK(toDependentPK); + forwardRelationship.setFK(fk); forwardRelationship.setToMany(toMany); // set relationship names only after their joins are ready ... @@ -146,11 +146,11 @@ private void checkAndAddRelationship(DbEntity entity, DbRelationship relationshi } } - private boolean isToMany(boolean toDependentPK, DbEntity fkEntity, DbRelationship forwardRelationship) { - return !toDependentPK || fkEntity.getPrimaryKeys().size() != forwardRelationship.getJoins().size(); + private boolean isToMany(boolean isFK, DbEntity fkEntity, DbRelationship forwardRelationship) { + return !isFK || fkEntity.getPrimaryKeys().size() != forwardRelationship.getJoins().size(); } - private boolean isToDependentPK(DbRelationship forwardRelationship) { + private boolean isFK(DbRelationship forwardRelationship) { for (DbJoin dbJoin : forwardRelationship.getJoins()) { if (!dbJoin.getTarget().isPrimaryKey()) { return false; From a8bc6fba0b832a23c5ef0a488f6cb28b00489069 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:04:32 +0100 Subject: [PATCH 07/14] modeler update --- .../apache/cayenne/map/DbRelationship.java | 15 +- .../modeler/DbRelationshipDialogView.java | 12 +- .../modeler/dialog/DbRelationshipDialog.java | 141 ++++++++++-------- .../dbentity/DbAttributeTableModel.java | 49 ++++-- .../dbentity/DbEntityRelationshipPanel.java | 2 +- .../dbentity/DbRelationshipTableModel.java | 63 ++++---- .../undo/RelationshipUndoableEdit.java | 2 +- .../cayenne/wocompat/EOModelProcessor.java | 4 +- 8 files changed, 156 insertions(+), 132 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java index fbacbb481f..afbff7d7ff 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java @@ -278,20 +278,7 @@ public void setFK(boolean FK) { */ public boolean isValidForFk() { // handle case with no joins - if (getJoins().size() == 0) { - return false; - } - - for (DbJoin join : getJoins()) { - DbAttribute target = join.getTarget(); - DbAttribute source = join.getSource(); - - if (target != null && !target.isPrimaryKey() || source != null && !source.isPrimaryKey()) { - return false; - } - } - - return true; + return getJoins().size() != 0; } /** diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java index d17eb1a9be..aa22983837 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/DbRelationshipDialogView.java @@ -46,7 +46,7 @@ public class DbRelationshipDialogView extends CayenneDialog { private JTextField name; private JComboBox targetEntities; - private JCheckBox toDepPk; + private JCheckBox fK; private JCheckBox toMany; private JTextField comment; private JLabel sourceName; @@ -71,7 +71,7 @@ public DbRelationshipDialogView() { private void initView() { name = new JTextField(25); targetEntities = new JComboBox<>(); - toDepPk = new JCheckBox(); + fK = new JCheckBox(); toMany = new JCheckBox(); comment = new JTextField(25); @@ -114,8 +114,8 @@ private void initView() { builder.addLabel("Target Entity:", cc.xy(1, 7)); builder.add(targetEntities, cc.xywh(3, 7, 1, 1)); - builder.addLabel("To Dep PK:", cc.xy(1, 9)); - builder.add(toDepPk, cc.xywh(3, 9, 1, 1)); + builder.addLabel("Foreign key:", cc.xy(1, 9)); + builder.add(fK, cc.xywh(3, 9, 1, 1)); builder.addLabel("To Many:", cc.xy(1, 11)); builder.add(toMany, cc.xywh(3, 11, 1, 1)); @@ -165,8 +165,8 @@ public JComboBox getTargetEntities() { return targetEntities; } - public JCheckBox getToDepPk() { - return toDepPk; + public JCheckBox getFK() { + return fK; } public JCheckBox getToMany() { diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java index c8d57ea76f..efe4e2161d 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/DbRelationshipDialog.java @@ -19,25 +19,10 @@ package org.apache.cayenne.modeler.dialog; -import javax.swing.AbstractListModel; -import javax.swing.ComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.JOptionPane; -import javax.swing.table.TableColumn; -import java.awt.Component; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.configuration.DataChannelDescriptor; import org.apache.cayenne.dbsync.naming.NameBuilder; +import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbJoin; import org.apache.cayenne.map.DbRelationship; @@ -55,6 +40,23 @@ import org.apache.cayenne.project.extension.info.ObjectInfo; import org.apache.cayenne.util.Util; +import javax.swing.AbstractListModel; +import javax.swing.ComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JOptionPane; +import javax.swing.event.TableModelEvent; +import javax.swing.table.TableColumn; +import java.awt.Component; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + /** * @since 4.2 */ @@ -125,15 +127,15 @@ private void initFromModel() { view.getTargetEntities().setModel(targetComboBoxModel); view.getSourceName().setText(relationship.getSourceEntityName()); - view.getToDepPk().setSelected(relationship.isToDependentPK()); + view.getFK().setSelected(relationship.isFK()); view.getToMany().setSelected(relationship.isToMany()); view.getNameField().setText(relationship.getName()); - if(reverseRelationship != null) { + if (reverseRelationship != null) { view.getReverseName().setText(reverseRelationship.getName()); } - if(relationship.getTargetEntity() == null) { + if (relationship.getTargetEntity() == null) { enableOptions(false); } else { enableInfo(); @@ -147,10 +149,10 @@ private void initFromModel() { private void initController() { view.getTargetEntities().addActionListener(action -> { - DbEntity selectedItem = ((TargetComboBoxModel)view.getTargetEntities().getModel()).selected; - if(relationship.getTargetEntityName() == null) { + DbEntity selectedItem = ((TargetComboBoxModel) view.getTargetEntities().getModel()).selected; + if (relationship.getTargetEntityName() == null) { relationship.setTargetEntityName(selectedItem.getName()); - } else if(!relationship.getTargetEntityName().equals(selectedItem.getName())){ + } else if (!relationship.getTargetEntityName().equals(selectedItem.getName())) { if (WarningDialogByDbTargetChange.showWarningDialog(projectController, relationship)) { // clear joins... relationship.removeAllJoins(); @@ -158,8 +160,8 @@ private void initController() { } else { view.getTargetEntities().setSelectedItem(relationship.getTargetEntityName()); } - relationship.setToDependentPK(false); - view.getToDepPk().setSelected(relationship.isValidForDepPk()); + relationship.setFK(false); + view.getFK().setSelected(relationship.isValidForFk()); projectController.fireDbRelationshipEvent(new RelationshipEvent(this, relationship, relationship.getSourceEntity())); } enableInfo(); @@ -183,12 +185,12 @@ private void initController() { DbJoin join = model.getJoin(row); relationship.removeJoin(join); - if(relationship.isValidForDepPk()) { - view.getToDepPk().setEnabled(true); + if (relationship.isValidForFk()) { + view.getFK().setEnabled(true); } else { - view.getToDepPk().setEnabled(false); - view.getToDepPk().setSelected(false); - relationship.setToDependentPK(false); + view.getFK().setEnabled(false); + view.getFK().setSelected(false); + relationship.setFK(false); } model.removeRow(join); @@ -206,27 +208,35 @@ private void initController() { view.setVisible(false); }); - view.addWindowListener(new WindowAdapter() - { + view.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { view.setCancelPressed(true); } }); - view.getToDepPk().setEnabled(relationship.isValidForDepPk()); - view.getToDepPk().addActionListener(selected -> { - boolean isSelected = view.getToDepPk().isSelected(); + view.getFK().setEnabled(relationship.isValidForFk()); + view.getFK().addActionListener(selected -> { + boolean isSelected = view.getFK().isSelected(); DbRelationship reverseRelationship = relationship.getReverseRelationship(); - if(reverseRelationship != null && reverseRelationship.isToDependentPK() && isSelected) { - boolean setToDepPk = JOptionPane.showConfirmDialog(Application.getFrame(), "Unset reverse relationship's \"To Dep PK\" setting?", - "Warning", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION; - relationship.setToDependentPK(setToDepPk); - reverseRelationship.setToDependentPK(!setToDepPk); + if (reverseRelationship != null) { + boolean isOKAnswer = JOptionPane.showConfirmDialog(Application.getFrame() + , isSelected ? "Foreign key will be unset in reverse relationship" : "Foreign key will be set in reverse relationship" + , "Warning" + , JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION; + if (isOKAnswer) { + relationship.setFK(isSelected); + reverseRelationship.setFK(!isSelected); + } else { + relationship.setFK(!isSelected); + reverseRelationship.setFK(isSelected); + view.getFK().setSelected(!isSelected); + } } else { - relationship.setToDependentPK(view.getToDepPk().isSelected()); + relationship.setFK(isSelected); } }); + } private void enableInfo() { @@ -236,12 +246,21 @@ private void enableInfo() { projectController, this, true)); view.getTable().getModel().addTableModelListener(change -> { - if(change.getLastRow() != Integer.MAX_VALUE) { - if(relationship.isValidForDepPk()) { - view.getToDepPk().setEnabled(true); - } else { - view.getToDepPk().setEnabled(false); + if (!isEventRowDeletion(change)) { + if (relationship.getReverseRelationship() == null) { + for (DbJoin join : relationship.getJoins()) { + if (!relationship.isFK()) { + DbAttribute target = join.getTarget(); + DbAttribute source = join.getSource(); + + if (target != null && source != null && target.isPrimaryKey() && !source.isPrimaryKey()) { + relationship.setFK(true); + view.getFK().setSelected(true); + } + } + } } + view.getFK().setEnabled(relationship.isValidForFk()); } }); @@ -262,6 +281,10 @@ private void enableInfo() { view.getTablePreferences().bind(view.getTable(), null, null, null, DbJoinTableModel.SOURCE, true); } + private boolean isEventRowDeletion(TableModelEvent change) { + return change.getLastRow() == Integer.MAX_VALUE; + } + private void enableOptions(boolean enable) { view.enableOptions(enable); } @@ -313,11 +336,11 @@ private void save() { if (relationship.getSourceEntity() == relationship.getTargetEntity()) { projectController .fireDbRelationshipEvent( - new RelationshipEvent( - this, - reverseRelationship, - reverseRelationship.getSourceEntity(), - MapEvent.ADD)); + new RelationshipEvent( + this, + reverseRelationship, + reverseRelationship.getSourceEntity(), + MapEvent.ADD)); } } else { handleNameUpdate(reverseRelationship, view.getReverseName().getText().trim()); @@ -327,8 +350,8 @@ private void save() { reverseRelationship.setJoins(reverseJoins); // check if joins map to a primary key of this entity - if (!relationship.isToDependentPK() && reverseRelationship.isValidForDepPk()) { - reverseRelationship.setToDependentPK(true); + if (!relationship.isFK() && reverseRelationship.isValidForFk()) { + reverseRelationship.setFK(true); } } @@ -336,7 +359,7 @@ private void save() { } private void handleNameUpdate(DbRelationship relationship, String userInputName) { - if(Util.nullSafeEquals(relationship.getName(), userInputName)) { + if (Util.nullSafeEquals(relationship.getName(), userInputName)) { return; } @@ -353,7 +376,7 @@ private void handleNameUpdate(DbRelationship relationship, String userInputName) projectController .fireDbRelationshipEvent( - new RelationshipEvent(this, relationship, relationship.getSourceEntity(), oldName)); + new RelationshipEvent(this, relationship, relationship.getSourceEntity(), oldName)); } private Collection getReverseJoins() { @@ -380,7 +403,7 @@ private Collection getReverseJoins() { } private void fireDbRelationshipEvent(boolean isCreate) { - if(!isCreate) { + if (!isCreate) { projectController .fireDbRelationshipEvent( new RelationshipEvent(this, relationship, relationship.getSourceEntity(), MapEvent.CHANGE)); @@ -388,7 +411,7 @@ private void fireDbRelationshipEvent(boolean isCreate) { Application.getInstance().getUndoManager().addEdit(undo); } else { DbEntity dbEntity = relationship.getSourceEntity(); - if(dbEntity.getRelationship(relationship.getName()) == null) { + if (dbEntity.getRelationship(relationship.getName()) == null) { dbEntity.addRelationship(relationship); } @@ -421,7 +444,7 @@ final class TargetComboBoxModel extends AbstractListModel implements Com } private String getTitle(DbEntity entity) { - if(entity == null) { + if (entity == null) { return ""; } return relationship.getSourceEntity().getDataMap() == entity.getDataMap() @@ -441,8 +464,8 @@ public String getElementAt(int index) { @Override public void setSelectedItem(Object anItem) { - String title = (String)anItem; - if(title != null) { + String title = (String) anItem; + if (title != null) { int spacer = title.indexOf(' '); if (spacer != -1) { title = title.substring(0, spacer); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java index 4998183fef..37697b99b5 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java @@ -53,12 +53,12 @@ public class DbAttributeTableModel extends CayenneTableModel { protected DbEntity entity; public DbAttributeTableModel(DbEntity entity, ProjectController mediator, - Object eventSource) { + Object eventSource) { this(entity, mediator, eventSource, new ArrayList<>(entity.getAttributes())); } public DbAttributeTableModel(DbEntity entity, ProjectController mediator, - Object eventSource, List objectList) { + Object eventSource, List objectList) { super(mediator, eventSource, objectList); this.entity = entity; } @@ -71,11 +71,11 @@ public int typeColumnInd() { return DB_ATTRIBUTE_TYPE; } - public int lengthColumnId(){ + public int lengthColumnId() { return DB_ATTRIBUTE_MAX; } - public int scaleColumnId(){ + public int scaleColumnId() { return DB_ATTRIBUTE_SCALE; } @@ -176,7 +176,7 @@ public void setUpdatedValueAt(Object newVal, int row, int col) { e.setOldName(attr.getName()); attr.setName((String) newVal); attr.getEntity().dbAttributeChanged(e); - + fireTableCellUpdated(row, col); break; case DB_ATTRIBUTE_TYPE: @@ -274,7 +274,7 @@ public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) { // when PK is unset, we need to fix some derived flags if (!flag) { - +//TODO OOOOOO attr.setGenerated(false); Collection relationships = ProjectUtil @@ -283,27 +283,44 @@ public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) { .addAll(ProjectUtil.getRelationshipsUsingAttributeAsSource(attr)); if (relationships.size() > 0) { - relationships.removeIf(relationship -> !relationship.isToDependentPK()); + relationships.removeIf(relationship -> !relationship.isFK()); // filtered only those that are to dep PK if (relationships.size() > 0) { - String message = (relationships.size() == 1) - ? "Fix \"To Dep PK\" relationship using this attribute?" + /* String message = (relationships.size() == 1) + ? "Fix \"Foreign key\" relationship using this attribute?" : "Fix " + relationships.size() - + " \"To Dep PK\" relationships using this attribute?"; + + " \"Foreign key\" relationships using this attribute?"; + */ + + + StringBuilder message = new StringBuilder("Removing an attribute can affect the following relationships:\n"); + for (DbRelationship relationship : relationships) { + message.append(relationship.getName()).append("\n"); + } + message.append("It would be a good idea to check them after making the change. Continue?"); + + /* JOptionPane.showMessageDialog(Application.getFrame() + , message + , "Warning" + , JOptionPane.PLAIN_MESSAGE); +*/ int answer = JOptionPane.showConfirmDialog( Application.getFrame(), - message); - if (answer != JOptionPane.YES_OPTION) { + message.toString(), + "Warning", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE); + if (answer != JOptionPane.OK_OPTION) { // no action needed return false; } - // fix target relationships + /* // fix target relationships for (DbRelationship relationship : relationships) { - relationship.setToDependentPK(false); - } + relationship.setFK(false); + }*/ } } } @@ -345,7 +362,7 @@ public boolean isColumnSortable(int sortCol) { @Override public void sortByColumn(int sortCol, boolean isAscent) { - switch(sortCol){ + switch (sortCol) { case DB_ATTRIBUTE_NAME: sortByElementProperty("name", isAscent); break; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java index 93080652b9..94cb094aec 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbEntityRelationshipPanel.java @@ -233,7 +233,7 @@ protected void rebuildTable(DbEntity entity) { targetCombo = Application.getWidgetFactory().createComboBox(); AutoCompletion.enable(targetCombo); - table.getColumnModel().getColumn(DbRelationshipTableModel.TO_DEPENDENT_KEY) + table.getColumnModel().getColumn(DbRelationshipTableModel.FK) .setCellRenderer(new CheckBoxCellRenderer()); targetCombo.setRenderer(CellRenderers.entityListRendererWithIcons(entity.getDataMap())); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java index cb27cad215..daf2f2834a 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbRelationshipTableModel.java @@ -35,21 +35,20 @@ /** * Table model for DbRelationship table. - * */ public class DbRelationshipTableModel extends CayenneTableModel { // Columns static final int NAME = 0; static final int TARGET = 1; - static final int TO_DEPENDENT_KEY = 2; + static final int FK = 2; static final int CARDINALITY = 3; static final int COMMENTS = 4; protected DbEntity entity; public DbRelationshipTableModel(DbEntity entity, ProjectController mediator, - Object eventSource) { + Object eventSource) { super(mediator, eventSource, new ArrayList<>(entity.getRelationships())); this.entity = entity; @@ -72,8 +71,8 @@ public String getColumnName(int col) { return "Name"; case TARGET: return "Target"; - case TO_DEPENDENT_KEY: - return "To Dep PK"; + case FK: + return "FK"; case CARDINALITY: return "To Many"; case COMMENTS: @@ -87,7 +86,7 @@ public Class getColumnClass(int col) { switch (col) { case TARGET: return DbEntity.class; - case TO_DEPENDENT_KEY: + case FK: case CARDINALITY: return Boolean.class; default: @@ -110,8 +109,8 @@ public Object getValueAt(int row, int col) { return rel.getName(); case TARGET: return rel.getTargetEntity(); - case TO_DEPENDENT_KEY: - return rel.isToDependentPK() ? Boolean.TRUE : Boolean.FALSE; + case FK: + return rel.isFK() ? Boolean.TRUE : Boolean.FALSE; case CARDINALITY: return rel.isToMany() ? Boolean.TRUE : Boolean.FALSE; case COMMENTS: @@ -138,35 +137,33 @@ public void setUpdatedValueAt(Object aValue, int row, int column) { rel.setName((String) aValue); mediator.fireDbRelationshipEvent(e); fireTableCellUpdated(row, column); - } else if (column == TO_DEPENDENT_KEY) { + } else if (column == FK) { boolean flag = (Boolean) aValue; - // make sure reverse relationship "to-dep-pk" is unset. - if (flag) { - DbRelationship reverse = rel.getReverseRelationship(); - if (reverse != null && reverse.isToDependentPK()) { - String message = "Unset reverse relationship's \"To Dep PK\" setting?"; - int answer = JOptionPane.showConfirmDialog( - Application.getFrame(), - message); - if (answer != JOptionPane.YES_OPTION) { - // no action needed - return; - } - - // unset reverse - reverse.setToDependentPK(false); + // set/unset FK at both ends of relationship. + DbRelationship reverse = rel.getReverseRelationship(); + if (reverse != null) { + boolean isOKAnswer = JOptionPane.showConfirmDialog(Application.getFrame() + , flag ? "Foreign key will be unset in reverse relationship" : "Foreign key will be set in reverse relationship" + , "Warning" + , JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION; + if (isOKAnswer) { + rel.setFK(flag); + reverse.setFK(!flag); + } else { + rel.setFK(!flag); + reverse.setFK(flag); } + } else { + rel.setFK(flag); } - - rel.setToDependentPK(flag); mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity)); } else if (column == CARDINALITY) { rel.setToMany((Boolean) aValue); mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity)); updateDependentObjRelationships(rel); - } else if(column == COMMENTS) { + } else if (column == COMMENTS) { setComment((String) aValue, rel); mediator.fireDbRelationshipEvent(new RelationshipEvent(eventSource, rel, entity)); } @@ -186,7 +183,7 @@ void updateDependentObjRelationships(DbRelationship relationship) { Collection objRelationshipsForDbRelationship = ProjectUtil .findObjRelationshipsForDbRelationship(mediator, relationship); - for(ObjRelationship objRelationship : objRelationshipsForDbRelationship) { + for (ObjRelationship objRelationship : objRelationshipsForDbRelationship) { objRelationship.recalculateToManyValue(); } } @@ -195,10 +192,10 @@ public boolean isCellEditable(int row, int col) { DbRelationship rel = getRelationship(row); if (rel == null) { return false; - } else if(col == TARGET) { + } else if (col == TARGET) { return false; - } else if (col == TO_DEPENDENT_KEY) { - return rel.isValidForDepPk(); + } else if (col == FK) { + return rel.isValidForFk(); } return true; } @@ -217,8 +214,8 @@ public void sortByColumn(int sortCol, boolean isAscent) { case TARGET: sortByElementProperty("targetEntityName", isAscent); break; - case TO_DEPENDENT_KEY: - sortByElementProperty("toDependentPK", isAscent); + case FK: + sortByElementProperty("FK", isAscent); break; case CARDINALITY: sortByElementProperty("toMany", isAscent); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java index 789a932735..ebd227ab9c 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java @@ -102,7 +102,7 @@ private Relationship copyRelationship(Relationship relationship) { private DbRelationship getDbRelationship(DbRelationship dbRelationship) { DbRelationship rel = new DbRelationship(); rel.setName(dbRelationship.getName()); - rel.setToDependentPK(dbRelationship.isToDependentPK()); + rel.setFK(dbRelationship.isFK()); rel.setToMany(dbRelationship.isToMany()); rel.setTargetEntityName(dbRelationship.getTargetEntityName()); rel.setSourceEntity(dbRelationship.getSourceEntity()); diff --git a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java index 3947f57148..0c518ca06d 100644 --- a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java +++ b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOModelProcessor.java @@ -597,7 +597,7 @@ protected void makeRelationships(EOModelHelper helper, ObjEntity objEntity) { String relName = (String) relMap.get("name"); boolean toMany = "Y".equals(relMap.get("isToMany")); - boolean toDependentPK = "Y".equals(relMap.get("propagatesPrimaryKey")); + boolean isFK = "Y".equals(relMap.get("propagatesPrimaryKey")); ObjEntity target = helper.getDataMap().getObjEntity(targetName); // target maybe null for cross-EOModel relationships @@ -629,7 +629,7 @@ protected void makeRelationships(EOModelHelper helper, ObjEntity objEntity) { dbRel.setTargetEntityName(dbTarget); dbRel.setToMany(toMany); dbRel.setName(relName); - dbRel.setToDependentPK(toDependentPK); + dbRel.setFK(isFK); dbSrc.addRelationship(dbRel); List joins = (List) relMap.get("joins"); From 0f839053211cdb2e031d5367fef90b9c75ce7069 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Mon, 27 Mar 2023 14:51:01 +0200 Subject: [PATCH 08/14] RelationshipLoader update --- .../reverse/dbload/RelationshipLoader.java | 24 +++++++------------ .../reverse/dbload/RelationshipsLoaderIT.java | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java index aa348c1c34..42360ddceb 100644 --- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java +++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipLoader.java @@ -76,6 +76,7 @@ public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLExcep DbRelationship forwardRelationship = new DbRelationship(); forwardRelationship.setSourceEntity(pkEntity); forwardRelationship.setTargetEntityName(fkEntity); + forwardRelationship.setFK(false); // TODO: dirty and non-transparent... using DbRelationshipDetected for the benefit of the merge package. // This info is available from joins.... @@ -84,14 +85,10 @@ public void load(DatabaseMetaData metaData, DbLoadDataStore map) throws SQLExcep reverseRelationship.setSourceEntity(fkEntity); reverseRelationship.setTargetEntityName(pkEntity); reverseRelationship.setToMany(false); - + reverseRelationship.setFK(true); createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship); - boolean fk = isFK(forwardRelationship); - boolean toMany = isToMany(fk, fkEntity, forwardRelationship); - - forwardRelationship.setFK(fk); - forwardRelationship.setToMany(toMany); + forwardRelationship.setToMany(isToMany(fkEntity,forwardRelationship)); // set relationship names only after their joins are ready ... // generator logic is based on relationship state... @@ -146,18 +143,13 @@ private void checkAndAddRelationship(DbEntity entity, DbRelationship relationshi } } - private boolean isToMany(boolean isFK, DbEntity fkEntity, DbRelationship forwardRelationship) { - return !isFK || fkEntity.getPrimaryKeys().size() != forwardRelationship.getJoins().size(); - } - - private boolean isFK(DbRelationship forwardRelationship) { - for (DbJoin dbJoin : forwardRelationship.getJoins()) { - if (!dbJoin.getTarget().isPrimaryKey()) { - return false; + private boolean isToMany(DbEntity fkEntity, DbRelationship forwardRelationship) { + for (DbJoin join : forwardRelationship.getJoins()) { + if (!join.getSource().isPrimaryKey() || !join.getTarget().isPrimaryKey()) { + return true; } } - - return true; + return fkEntity.getPrimaryKeys().size() != forwardRelationship.getJoins().size(); } private void createAndAppendJoins(Set exportedKeys, DbEntity pkEntity, DbEntity fkEntity, diff --git a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java index 2c0189a0eb..7b78c61082 100644 --- a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java +++ b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/dbload/RelationshipsLoaderIT.java @@ -76,7 +76,7 @@ public void testRelationshipLoad() throws Exception { assertNotNull("No relationship to PAINTING_INFO", oneToOne); assertFalse("Relationship to PAINTING_INFO must be to-one", oneToOne.isToMany()); - assertTrue("Relationship to PAINTING_INFO must be to-one", oneToOne.isFK()); + assertTrue("Relationship to PAINTING_INFO must be to-one", !oneToOne.isFK()); } // private void assertUniqueConstraintsInRelationships(DataMap map) { From 1c55d29ebc903d7fa2be2d44f11b66dfeca401f9 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Mon, 27 Mar 2023 14:51:39 +0200 Subject: [PATCH 09/14] rename in DbRelationshipValidator --- .../project/validation/DbRelationshipValidator.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DbRelationshipValidator.java b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DbRelationshipValidator.java index 9fffbbc0f3..4543e74524 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DbRelationshipValidator.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DbRelationshipValidator.java @@ -137,14 +137,13 @@ private void checkTypesOfAttributesInRelationship(DbRelationship relationship, V } private void checkOnGeneratedStrategyConflict(DbRelationship relationship, ValidationResult validationResult) { - if (relationship.isToDependentPK()) { - Collection attributes = relationship.getTargetEntity().getGeneratedAttributes(); - for (DbAttribute attribute : attributes) { - if (attribute.isGenerated()) { + if (relationship.isFK()) { + for (DbJoin join : relationship.getJoins()) { + if (join.getSource().isGenerated()) { addFailure( validationResult, relationship, - "'To Dep Pk' incompatible with Database-Generated on '%s' relationship", + "'FK' incompatible with Database-Generated on '%s' relationship", toString(relationship)); } } From e0956b1d69b0b82ae124517aa0166728b26b1e51 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka Date: Tue, 4 Apr 2023 16:37:20 +0300 Subject: [PATCH 10/14] ToDepPkToFkUpdater added --- .../upgrade/DefaultUpgradeService.java | 2 +- .../upgrade/handlers/UpgradeHandler.java | 6 + .../upgrade/handlers/UpgradeHandler_V11.java | 8 + .../upgrade/utils/ToDepPkToFkUpdater.java | 251 ++++++++++++++++++ .../upgrade/DefaultUpgradeServiceTest.java | 2 +- .../handlers/BaseUpgradeHandlerTest.java | 15 ++ .../handlers/UpgradeHandler_V11Test.java | 78 ++++++ .../upgrade/handlers/fkTestmap-1.map.xml | 135 ++++++++++ .../upgrade/handlers/fkTestmap-2.map.xml | 16 ++ 9 files changed, 511 insertions(+), 2 deletions(-) create mode 100644 cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java create mode 100644 cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-1.map.xml create mode 100644 cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-2.map.xml diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java index ceafe92a23..ee9a16936f 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/DefaultUpgradeService.java @@ -187,8 +187,8 @@ protected List upgradeDOM(Resource resource, List h for(UpgradeUnit dataMapUnit : dataMapUnits) { handler.processDataMapDom(dataMapUnit); } + handler.processAllDataMapDomes(dataMapUnits); } - return allUnits; } diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java index e0818a261b..27219711ca 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler.java @@ -29,6 +29,8 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import java.util.List; + /** * Interface that upgrade handlers should implement. * Implementation also should be injected into DI stack in right order. @@ -108,4 +110,8 @@ default void updateExtensionSchema(UpgradeUnit upgradeUnit, String extension) { element.setAttribute("xmlns", "http://cayenne.apache.org/schema/"+getVersion()+"/"+extension); } } + + default void processAllDataMapDomes(List dataMapUnits) { + //noop + } } diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java index efa19727f2..6d92453d88 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java @@ -20,6 +20,7 @@ package org.apache.cayenne.project.upgrade.handlers; import org.apache.cayenne.project.upgrade.UpgradeUnit; +import org.apache.cayenne.project.upgrade.utils.ToDepPkToFkUpdater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; @@ -36,6 +37,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -87,6 +89,12 @@ public void processDataMapDom(UpgradeUnit upgradeUnit) { updateDbImportConfig(upgradeUnit); } + @Override + public void processAllDataMapDomes(List dataMapUnits) { + ToDepPkToFkUpdater fkUpdater = new ToDepPkToFkUpdater(); + fkUpdater.update(dataMapUnits); + } + private void upgradeComments(UpgradeUnit upgradeUnit) { XPath xpath = XPathFactory.newInstance().newXPath(); NodeList infoNodes; diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java new file mode 100644 index 0000000000..b24aa621f2 --- /dev/null +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java @@ -0,0 +1,251 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.project.upgrade.utils; + +import org.apache.cayenne.project.upgrade.UpgradeUnit; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.ArrayList; +import java.util.List; + +public class ToDepPkToFkUpdater { + + private static final String TO_DEP_PK_TAG = "toDependentPK"; + private static final String FK_TAG = "fk"; + private static final String DB_RELATIONSHIP_TAG = "db-relationship"; + private static final String DB_ENTITY_TAG = "db-entity"; + private static final String DB_ATTRIBUTE_PAIR_TAG = "db-attribute-pair"; + + public void update(List units) { + + List dataMaps = new ArrayList<>(units.size()); + List combinedDbEntityList = new ArrayList<>(); + + for (UpgradeUnit upgradeUnit : units) { + Element dataMap = upgradeUnit.getDocument().getDocumentElement(); + dataMaps.add(dataMap); + combinedDbEntityList.add(dataMap.getElementsByTagName(DB_ENTITY_TAG)); + } + + for (Element dataMap : dataMaps) { + NodeList relationships = dataMap.getElementsByTagName(DB_RELATIONSHIP_TAG); + + for (int i = 0; i < relationships.getLength(); i++) { + Node relationship = relationships.item(i); + + Element reverseRelationship = findReverseRelationship(relationships, relationship); + + if (reverseRelationship == null) { + reverseRelationship = findReverseInAllDatamaps(dataMaps, relationship); + } + + if (!isToDepPK(relationship) + && !isToDepPK(reverseRelationship) + && !isFK(relationship) + && !isFK(reverseRelationship)) { + setFk((Element) relationship, reverseRelationship, combinedDbEntityList); + } + + if (isToDepPK(relationship)) { + handleToDepPK(relationship, reverseRelationship, combinedDbEntityList); + } + } + } + } + + private Element findReverseInAllDatamaps(List dataMaps, Node relationship) { + for (Element dataMap : dataMaps) { + NodeList relationships = dataMap.getElementsByTagName(DB_RELATIONSHIP_TAG); + Element reverseRelationship = findReverseRelationship(relationships, relationship); + if (reverseRelationship != null) { + return reverseRelationship; + } + } + return null; + } + + private void setFk(Element relationship, Element reverseRelationship, List combinedDbEntityList) { + NodeList pairNodes = relationship.getElementsByTagName(DB_ATTRIBUTE_PAIR_TAG); + for (int i = 0; i < pairNodes.getLength(); i++) { + String joinSource = pairNodes.item(i).getAttributes().getNamedItem("source").getNodeValue(); + String joinTarget = pairNodes.item(i).getAttributes().getNamedItem("target").getNodeValue(); + + NamedNodeMap relationshipAttrs = relationship.getAttributes(); + + String sourceEntityName = relationshipAttrs.getNamedItem("source").getNodeValue(); + String targetEntityName = relationshipAttrs.getNamedItem("target").getNodeValue(); + + Node sourceEntity = getDbEntityByName(combinedDbEntityList, sourceEntityName); + Node targetEntity = getDbEntityByName(combinedDbEntityList, targetEntityName); + + if (sourceEntity != null && targetEntity != null) { + + boolean sourceIsPrimaryKey = isPrimaryKey(joinSource, sourceEntity.getChildNodes()); + boolean targetIsPrimaryKey = isPrimaryKey(joinTarget, targetEntity.getChildNodes()); + + if (sourceIsPrimaryKey != targetIsPrimaryKey) { + if (reverseRelationship != null && sourceIsPrimaryKey) { + reverseRelationship.setAttribute(FK_TAG, "true"); + } + if (reverseRelationship != null && !sourceIsPrimaryKey) { + relationship.setAttribute(FK_TAG, "true"); + } + + if (reverseRelationship == null && !sourceIsPrimaryKey) { + relationship.setAttribute(FK_TAG, "true"); + } + return; + } + } + } + } + + private boolean isPrimaryKey(String joinName, NodeList childNodes) { + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (item.getAttributes() != null) { + String name = item.getAttributes().getNamedItem("name").getNodeValue(); + if (name.equals(joinName)) { + Node isPrimaryKey = item.getAttributes().getNamedItem("isPrimaryKey"); + if (isPrimaryKey != null) { + return isPrimaryKey.getNodeValue().equals("true"); + } + } + } + } + return false; + } + + private Node getDbEntityByName(List combinedDbEntityList, String searchedEntityName) { + for (NodeList list : combinedDbEntityList) { + for (int i = 0; i < list.getLength(); i++) { + String entityName = list.item(i).getAttributes().getNamedItem("name").getNodeValue(); + if (searchedEntityName.equals(entityName)) { + return list.item(i); + } + } + } + return null; + } + + private boolean isToDepPK(Node relationship) { + if (relationship == null) { + return false; + } + NamedNodeMap relationshipAttrs = relationship.getAttributes(); + Node toDependentPK = relationshipAttrs.getNamedItem(TO_DEP_PK_TAG); + return toDependentPK != null && toDependentPK.getNodeValue().equalsIgnoreCase("true"); + } + + private boolean isFK(Node relationship) { + if (relationship == null) { + return false; + } + NamedNodeMap relationshipAttrs = relationship.getAttributes(); + Node fkNode = relationshipAttrs.getNamedItem(FK_TAG); + return fkNode != null && fkNode.getNodeValue().equalsIgnoreCase("true"); + } + + private void handleToDepPK(Node relationship, Element reverseRelationship, List combinedDbEntityList) { + relationship.getAttributes().removeNamedItem(TO_DEP_PK_TAG); + if (reverseRelationship != null) { + if (!isToDepPK(reverseRelationship)) { + reverseRelationship.setAttribute(FK_TAG, "true"); + } else { + reverseRelationship.getAttributes().removeNamedItem(TO_DEP_PK_TAG); + setFk((Element) relationship, reverseRelationship, combinedDbEntityList); + } + } + } + + private Element findReverseRelationship(NodeList dbRelationshipList, Node dbRelationshipNode) { + Element dbRelationship = (Element) dbRelationshipNode; + + String sourceAttr = dbRelationship.getAttribute("source"); + String targetAttr = dbRelationship.getAttribute("target"); + + List pairs = getDbAttrPairs(dbRelationship); + + for (int j = 0; j < dbRelationshipList.getLength(); j++) { + Node candidateDbRelationshipNode = dbRelationshipList.item(j); + if (candidateDbRelationshipNode.getNodeType() == Node.ELEMENT_NODE) { + Element candidateDbRelationship = (Element) candidateDbRelationshipNode; + if (isCandidateSuitable(sourceAttr, targetAttr, pairs, candidateDbRelationship)) { + return candidateDbRelationship; + } + } + } + return null; + } + + private boolean isCandidateSuitable(String sourceAttr, String targetAttr, List pairs, Element candidateDbRelationship) { + String candidateSourceAttr = candidateDbRelationship.getAttribute("source"); + String candidateTargetAttr = candidateDbRelationship.getAttribute("target"); + + List candidatePairs = getDbAttrPairs(candidateDbRelationship); + + return sourceAttr.equals(candidateTargetAttr) + && targetAttr.equals(candidateSourceAttr) + && pairs.size() == candidatePairs.size() + && containAllReversed(pairs, candidatePairs); + } + + private boolean containAllReversed(List pairs, List candidatePairs) { + return pairs.stream() + .allMatch(pair -> candidatePairs.stream().anyMatch(pair::isReverseFor)); + } + + private List getDbAttrPairs(Element dbRelationship) { + List pairs = new ArrayList<>(); + NodeList attributes = dbRelationship.getElementsByTagName(DB_ATTRIBUTE_PAIR_TAG); + for (int j = 0; j < attributes.getLength(); j++) { + Node attributeNode = attributes.item(j); + if (attributeNode.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) attributeNode; + String pairSource = element.getAttribute("source"); + String pairTarget = element.getAttribute("target"); + pairs.add(new DbAttrPair(pairSource, pairTarget)); + } + } + return pairs; + } + + private static class DbAttrPair { + private final String source; + private final String target; + + public DbAttrPair(String source, String target) { + this.source = source; + this.target = target; + } + + private boolean isReverseFor(DbAttrPair pair) { + return this.source.equals(pair.target) && this.target.equals(pair.source); + } + + } +} + + + + diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java index a2ba5ca124..3d594ccfec 100644 --- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java @@ -131,7 +131,7 @@ public void upgradeDOM() throws Exception { verify(handler).processProjectDom(any(UpgradeUnit.class)); // two data maps verify(handler, times(2)).processDataMapDom(any(UpgradeUnit.class)); - verifyNoMoreInteractions(handler); + // verifyNoMoreInteractions(handler); } } diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java index e021b15900..9cf1266cca 100644 --- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/BaseUpgradeHandlerTest.java @@ -21,6 +21,8 @@ import java.io.InputStreamReader; import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -58,6 +60,19 @@ Document processDataMapDom(String xmlResourceName) throws Exception { return unit.getDocument(); } + List processAllDataMapDomes(List xmlResourceNames) throws Exception { + List upgradeUnits = new ArrayList<>(xmlResourceNames.size()); + List documents = new ArrayList<>(); + for (String xmlResourceName : xmlResourceNames) { + UpgradeUnit unit = new UpgradeUnit(new URLResource(getClass().getResource(xmlResourceName)), + documentFromResource(xmlResourceName)); + upgradeUnits.add(unit); + documents.add(unit.getDocument()); + } + handler.processAllDataMapDomes(upgradeUnits); + return documents; + } + Document documentFromString(String xml) throws Exception { DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return db.parse(new InputSource(new StringReader(xml))); diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java index b5419295de..c52b5a54b0 100644 --- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java @@ -27,7 +27,12 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import java.util.Arrays; +import java.util.List; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; @@ -181,6 +186,79 @@ public void testDbImportDomUpgrade() throws Exception { assertEquals(1, elements); } + @Test + public void testToDepPkToFkUpgrade() throws Exception { + List resources = Arrays.asList( "fkTestmap-1.map.xml","fkTestmap-2.map.xml"); + List documents = processAllDataMapDomes(resources); + Document fkTestmap_1 = documents.get(0); + Document fkTestmap_2 = documents.get(1); + + Element rootMap_1 = fkTestmap_1.getDocumentElement(); + NodeList dbRelationshipsMap_1 = rootMap_1.getElementsByTagName("db-relationship"); + + Element rootMap_2 = fkTestmap_2.getDocumentElement(); + NodeList dbRelationshipsMap_2 = rootMap_2.getElementsByTagName("db-relationship"); + + for (int i = 0; i < dbRelationshipsMap_1.getLength(); i++) { + NamedNodeMap attributes = dbRelationshipsMap_1.item(i).getAttributes(); + String name = attributes.getNamedItem("name").getNodeValue(); + Node fk = attributes.getNamedItem("fk"); + switch (name) { + case "reverse_several_matching_joins": + case "noReverse_fk": + case "joinsAnotherOrder": + case "toDepPk": + case "nPk_Pk": + case "toDepPK_toDepPK": + assertNotNull(fk); + assertEquals(fk.getNodeValue(), "true"); + break; + + case "nPk_nPk": + case "reverse_nPk_nPk": + case "noReverse_notFk": + case "reverse_nPk_Pk": + case "reverse_PK_PK": + case "PK_PK": + case "several_matching_joins": + case "reverse_toDepPK_toDepPK": + assertNull(fk); + break; + } + } + + for (int i = 0; i < dbRelationshipsMap_2.getLength(); i++) { + NamedNodeMap attributes = dbRelationshipsMap_2.item(i).getAttributes(); + String name = attributes.getNamedItem("name").getNodeValue(); + Node fk = attributes.getNamedItem("fk"); + switch (name) { + case "reverse_reverseInAnotherDatamap": + case "reverse_reverseInAnotherDatamapToDepPK": + assertNotNull(fk); + assertEquals(fk.getNodeValue(), "true"); + break; + } + } + + for (int i = 0; i < dbRelationshipsMap_1.getLength(); i++) { + NamedNodeMap attributes = dbRelationshipsMap_1.item(i).getAttributes(); + String name = attributes.getNamedItem("name").getNodeValue(); + Node toDepPK = attributes.getNamedItem("toDependentPK"); + switch (name) { + case "reverse_toDepPk": + case "reverseInAnotherDatamapToDepPK": + case "toDepPK_toDepPK": + case "reverse_toDepPK_toDepPK": + assertNull(toDepPK); + break; + } + } + + assertEquals(18, dbRelationshipsMap_1.getLength()); + assertEquals(2, dbRelationshipsMap_2.getLength()); + + } + @Test public void testModelUpgrade() { DataChannelDescriptor descriptor = mock(DataChannelDescriptor.class); diff --git a/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-1.map.xml b/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-1.map.xml new file mode 100644 index 0000000000..81e93ab510 --- /dev/null +++ b/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-1.map.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-2.map.xml b/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-2.map.xml new file mode 100644 index 0000000000..e0383b5b11 --- /dev/null +++ b/cayenne-project/src/test/resources/org/apache/cayenne/project/upgrade/handlers/fkTestmap-2.map.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From 9835613e905737adfc6fa78c1de38c3660339e57 Mon Sep 17 00:00:00 2001 From: Ivan Nikitka Date: Fri, 7 Apr 2023 17:00:48 +0300 Subject: [PATCH 11/14] comments update --- .../flush/ArcValuesCreationHandler.java | 4 ++-- .../java/org/apache/cayenne/map/DbEntity.java | 2 +- .../dbentity/DbAttributeTableModel.java | 21 +------------------ 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java index 6abd47744c..1b3cecc4e9 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java @@ -172,8 +172,8 @@ protected void processRelationship(DbRelationship dbRelationship, ObjectId srcId // We manage 3 cases here: // 1. PK -> FK: just propagate value from PK and to FK - // 2. PK -> PK: check isToDep flag and set dependent one - // 3. NON-PK -> FK (not supported fully for now, see CAY-2488): also check isToDep flag, + // 2. PK -> PK: check isFk flag and set dependent one + // 3. NON-PK -> FK (not supported fully for now, see CAY-2488): also check isFk flag, // but get value from DbRow, not ObjID if(srcPK != targetPK) { // case 1 diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java index 67b984dd6c..a67d22a7a1 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java @@ -423,7 +423,7 @@ private void handleAttributeUpdate(AttributeEvent e) { } } - // check toDep PK for reverse relationships + // check isFk for reverse relationships for (DbRelationship rel : getRelationships()) { DbRelationship reverse = rel.getReverseRelationship(); if(reverse != null && reverse.isFK() && !reverse.isValidForFk()) { diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java index 37697b99b5..0a41d196e9 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/dbentity/DbAttributeTableModel.java @@ -274,7 +274,6 @@ public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) { // when PK is unset, we need to fix some derived flags if (!flag) { -//TODO OOOOOO attr.setGenerated(false); Collection relationships = ProjectUtil @@ -285,27 +284,14 @@ public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) { if (relationships.size() > 0) { relationships.removeIf(relationship -> !relationship.isFK()); - // filtered only those that are to dep PK + // filtered only those that are isFk if (relationships.size() > 0) { - /* String message = (relationships.size() == 1) - ? "Fix \"Foreign key\" relationship using this attribute?" - : "Fix " + relationships.size() - + " \"Foreign key\" relationships using this attribute?"; - */ - - StringBuilder message = new StringBuilder("Removing an attribute can affect the following relationships:\n"); for (DbRelationship relationship : relationships) { message.append(relationship.getName()).append("\n"); } message.append("It would be a good idea to check them after making the change. Continue?"); - - /* JOptionPane.showMessageDialog(Application.getFrame() - , message - , "Warning" - , JOptionPane.PLAIN_MESSAGE); -*/ int answer = JOptionPane.showConfirmDialog( Application.getFrame(), message.toString(), @@ -316,11 +302,6 @@ public boolean setPrimaryKey(Boolean newVal, DbAttribute attr, int row) { // no action needed return false; } - - /* // fix target relationships - for (DbRelationship relationship : relationships) { - relationship.setFK(false); - }*/ } } } From 3866ac43948d1f9eed2820ead7d247a7d06fd75f Mon Sep 17 00:00:00 2001 From: Ivan Nikitka Date: Fri, 7 Apr 2023 17:02:12 +0300 Subject: [PATCH 12/14] move to handlers package --- .../cayenne/project/upgrade/handlers/UpgradeHandler_V11.java | 3 +-- .../upgrade/{utils => handlers/v11}/ToDepPkToFkUpdater.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) rename cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/{utils => handlers/v11}/ToDepPkToFkUpdater.java (99%) diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java index 6d92453d88..972235b8f0 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11.java @@ -20,7 +20,7 @@ package org.apache.cayenne.project.upgrade.handlers; import org.apache.cayenne.project.upgrade.UpgradeUnit; -import org.apache.cayenne.project.upgrade.utils.ToDepPkToFkUpdater; +import org.apache.cayenne.project.upgrade.handlers.v11.ToDepPkToFkUpdater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; @@ -37,7 +37,6 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java similarity index 99% rename from cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java rename to cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java index b24aa621f2..d306ab97c5 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/utils/ToDepPkToFkUpdater.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.project.upgrade.utils; +package org.apache.cayenne.project.upgrade.handlers.v11; import org.apache.cayenne.project.upgrade.UpgradeUnit; import org.w3c.dom.Element; From 64dd442fed2a182efe2b1bbc75dc422f0545bb6d Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:51:26 +0200 Subject: [PATCH 13/14] ToDepPkToFkUpdater refactoring --- .../handlers/v11/ToDepPkToFkUpdater.java | 72 ++++++++++++------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java index d306ab97c5..b1fa0eb72b 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/upgrade/handlers/v11/ToDepPkToFkUpdater.java @@ -20,6 +20,8 @@ package org.apache.cayenne.project.upgrade.handlers.v11; import org.apache.cayenne.project.upgrade.UpgradeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -36,6 +38,8 @@ public class ToDepPkToFkUpdater { private static final String DB_ENTITY_TAG = "db-entity"; private static final String DB_ATTRIBUTE_PAIR_TAG = "db-attribute-pair"; + private static final Logger logger = LoggerFactory.getLogger(ToDepPkToFkUpdater.class); + public void update(List units) { List dataMaps = new ArrayList<>(units.size()); @@ -85,42 +89,56 @@ private Element findReverseInAllDatamaps(List dataMaps, Node relationsh } private void setFk(Element relationship, Element reverseRelationship, List combinedDbEntityList) { - NodeList pairNodes = relationship.getElementsByTagName(DB_ATTRIBUTE_PAIR_TAG); - for (int i = 0; i < pairNodes.getLength(); i++) { - String joinSource = pairNodes.item(i).getAttributes().getNamedItem("source").getNodeValue(); - String joinTarget = pairNodes.item(i).getAttributes().getNamedItem("target").getNodeValue(); - NamedNodeMap relationshipAttrs = relationship.getAttributes(); - - String sourceEntityName = relationshipAttrs.getNamedItem("source").getNodeValue(); - String targetEntityName = relationshipAttrs.getNamedItem("target").getNodeValue(); - - Node sourceEntity = getDbEntityByName(combinedDbEntityList, sourceEntityName); - Node targetEntity = getDbEntityByName(combinedDbEntityList, targetEntityName); + Node sourceEntity = getDbEntityByJoinDirection(combinedDbEntityList, relationship, "source"); + Node targetEntity = getDbEntityByJoinDirection(combinedDbEntityList, relationship, "target"); + NodeList pairNodes = relationship.getElementsByTagName(DB_ATTRIBUTE_PAIR_TAG); + for (int i = 0; i < pairNodes.getLength(); i++) { if (sourceEntity != null && targetEntity != null) { + Node currentNode = pairNodes.item(i); - boolean sourceIsPrimaryKey = isPrimaryKey(joinSource, sourceEntity.getChildNodes()); - boolean targetIsPrimaryKey = isPrimaryKey(joinTarget, targetEntity.getChildNodes()); + boolean sourceIsPK = isPrimaryKey(sourceEntity, currentNode, "source"); + boolean targetIsPK = isPrimaryKey(targetEntity, currentNode, "target"); - if (sourceIsPrimaryKey != targetIsPrimaryKey) { - if (reverseRelationship != null && sourceIsPrimaryKey) { - reverseRelationship.setAttribute(FK_TAG, "true"); - } - if (reverseRelationship != null && !sourceIsPrimaryKey) { - relationship.setAttribute(FK_TAG, "true"); - } - - if (reverseRelationship == null && !sourceIsPrimaryKey) { - relationship.setAttribute(FK_TAG, "true"); - } + if (sourceIsPK != targetIsPK) { + handleDefinedFkCase(relationship, reverseRelationship, sourceIsPK); return; + } else { + handleUndefinedFkCase(relationship, reverseRelationship, pairNodes, i); } } } } - private boolean isPrimaryKey(String joinName, NodeList childNodes) { + private void handleUndefinedFkCase(Element relationship, Element reverseRelationship, NodeList pairNodes, int i) { + //Check is this last join, which means there are no joins where fk direction is defined and this + // relationship has both side. + if (isLastJoinPair(pairNodes, i) && reverseRelationship != null) { + relationship.setAttribute(FK_TAG, "true"); + logger.warn(String.format("Foreign key in relationships pair %s and %s was undefined. FK = true was set in the %s by default" + , relationship.getAttribute("name") + , reverseRelationship.getAttribute("name") + , relationship.getAttribute("name"))); + } + } + + private void handleDefinedFkCase(Element relationship, Element reverseRelationship, boolean sourceIsPK) { + if (sourceIsPK && reverseRelationship != null) { + reverseRelationship.setAttribute(FK_TAG, "true"); + } + if (!sourceIsPK) { + relationship.setAttribute(FK_TAG, "true"); + } + } + + private boolean isLastJoinPair(NodeList pairNodes, int i) { + return i == pairNodes.getLength() - 1; + } + + private boolean isPrimaryKey(Node entity, Node node, String joinDirection) { + String joinName = node.getAttributes().getNamedItem(joinDirection).getNodeValue(); + NodeList childNodes = entity.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node item = childNodes.item(i); if (item.getAttributes() != null) { @@ -136,7 +154,9 @@ private boolean isPrimaryKey(String joinName, NodeList childNodes) { return false; } - private Node getDbEntityByName(List combinedDbEntityList, String searchedEntityName) { + private Node getDbEntityByJoinDirection(List combinedDbEntityList, Element relationship, String joinDirection) { + NamedNodeMap relationshipAttrs = relationship.getAttributes(); + String searchedEntityName = relationshipAttrs.getNamedItem(joinDirection).getNodeValue(); for (NodeList list : combinedDbEntityList) { for (int i = 0; i < list.getLength(); i++) { String entityName = list.item(i).getAttributes().getNamedItem("name").getNodeValue(); From 135ab2469e02679fa1489edee3ce4110574f67bf Mon Sep 17 00:00:00 2001 From: Ivan Nikitka <70625960+Ivan-nikitko@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:52:16 +0200 Subject: [PATCH 14/14] tests updating --- .../cayenne/project/upgrade/DefaultUpgradeServiceTest.java | 3 ++- .../project/upgrade/handlers/UpgradeHandler_V11Test.java | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java index 3d594ccfec..c0f4822736 100644 --- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/DefaultUpgradeServiceTest.java @@ -131,7 +131,8 @@ public void upgradeDOM() throws Exception { verify(handler).processProjectDom(any(UpgradeUnit.class)); // two data maps verify(handler, times(2)).processDataMapDom(any(UpgradeUnit.class)); - // verifyNoMoreInteractions(handler); + verify(handler).processAllDataMapDomes(anyList()); + verifyNoMoreInteractions(handler); } } diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java index c52b5a54b0..fc6b826402 100644 --- a/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/upgrade/handlers/UpgradeHandler_V11Test.java @@ -209,17 +209,16 @@ public void testToDepPkToFkUpgrade() throws Exception { case "joinsAnotherOrder": case "toDepPk": case "nPk_Pk": + case "nPk_nPk": + case "PK_PK": case "toDepPK_toDepPK": assertNotNull(fk); assertEquals(fk.getNodeValue(), "true"); break; - - case "nPk_nPk": - case "reverse_nPk_nPk": case "noReverse_notFk": case "reverse_nPk_Pk": + case "reverse_nPk_nPk": case "reverse_PK_PK": - case "PK_PK": case "several_matching_joins": case "reverse_toDepPK_toDepPK": assertNull(fk);