From b2b61d7b62b83d4a36934d131e19293e97b900bf Mon Sep 17 00:00:00 2001 From: sonika-shah <58761340+sonika-shah@users.noreply.github.com> Date: Wed, 3 Sep 2025 08:26:10 +0530 Subject: [PATCH] Fix Data Product to asset mapping lost after upgrade (#23195) --- .../service/jdbi3/EntityRepository.java | 36 ++++++++++- .../service/resources/EntityResourceTest.java | 63 +++++++++++++++++-- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java index b5958897f32..3fafc88f4ab 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java @@ -5376,7 +5376,7 @@ public abstract class EntityRepository { } private Map> batchFetchDataProducts(List entities) { - return batchFetchFromIdsManyToOne(entities, Relationship.HAS, Entity.DATA_PRODUCT); + return batchFetchToIdsOneToMany(entities, Relationship.HAS, Entity.DATA_PRODUCT); } private Map batchFetchCertification(List entities) { @@ -5682,6 +5682,40 @@ public abstract class EntityRepository { return resultMap; } + protected Map> batchFetchToIdsOneToMany( + List entities, Relationship relationship, String fromEntityType) { + var resultMap = new HashMap>(); + if (entities == null || entities.isEmpty()) { + return resultMap; + } + + // Use Include.ALL to get all relationships including those for soft-deleted entities + var records = + daoCollection + .relationshipDAO() + .findFromBatch( + entityListToStrings(entities), relationship.ordinal(), fromEntityType, ALL); + + var idReferenceMap = + Entity.getEntityReferencesByIds( + fromEntityType, + records.stream().map(e -> UUID.fromString(e.getFromId())).distinct().toList(), + ALL) + .stream() + .collect(Collectors.toMap(e -> e.getId().toString(), Function.identity())); + + records.forEach( + record -> { + var entityId = UUID.fromString(record.getToId()); + var relatedRef = idReferenceMap.get(record.getFromId()); + if (relatedRef != null) { + resultMap.computeIfAbsent(entityId, k -> new ArrayList<>()).add(relatedRef); + } + }); + + return resultMap; + } + protected Map batchFetchFromIdsAndRelationSingleRelation( List entities, Relationship relationship) { var resultMap = new HashMap(); diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java index ecbaa34d125..7264213faed 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/EntityResourceTest.java @@ -866,6 +866,18 @@ public abstract class EntityResourceTest params = new HashMap<>(); @@ -926,12 +945,20 @@ public abstract class EntityResourceTest d.getId().equals(domain1Id)), @@ -1021,12 +1047,39 @@ public abstract class EntityResourceTest batchDataProducts = listOrEmpty(batchEntityFound.getDataProducts()); + List indivDataProducts = listOrEmpty(individualEntity.getDataProducts()); + + assertEquals( + indivDataProducts.size(), + batchDataProducts.size(), + "DataProducts count mismatch between batch and individual fetch - This is the bug!"); + + if (!indivDataProducts.isEmpty()) { + assertFalse( + batchDataProducts.isEmpty(), + "Batch DataProducts empty when individual has them - This is the exact bug!"); + + final UUID dataProductId = testDataProduct.getId(); + assertTrue( + batchDataProducts.stream().anyMatch(dp -> dp.getId().equals(dataProductId)), + "Should find test data product in batch DataProducts"); + assertTrue( + indivDataProducts.stream().anyMatch(dp -> dp.getId().equals(dataProductId)), + "Should find test data product in individual DataProducts"); + } + } + LOG.info("Successfully verified field combination: {}", fields); } } finally { if (supportsOwners) userResourceTest.deleteEntity(testUser.getId(), ADMIN_AUTH_HEADERS); if (supportsTags) tagResourceTest.deleteEntity(testTag.getId(), ADMIN_AUTH_HEADERS); + if (supportsDataProducts && testDataProduct != null) { + dataProductResourceTest.deleteEntity(testDataProduct.getId(), ADMIN_AUTH_HEADERS); + } if (supportsDomains) { domainResourceTest.deleteEntity(testDomain1.getId(), ADMIN_AUTH_HEADERS); domainResourceTest.deleteEntity(testDomain2.getId(), ADMIN_AUTH_HEADERS);