@@ -24,6 +24,7 @@ internal class DataverseService
2424 private readonly EntityIconService entityIconService ;
2525 private readonly RecordMappingService recordMappingService ;
2626 private readonly SolutionComponentService solutionComponentService ;
27+ private readonly SolutionComponentExtractor solutionComponentExtractor ;
2728 private readonly WorkflowService workflowService ;
2829 private readonly RelationshipService relationshipService ;
2930
@@ -38,6 +39,7 @@ public DataverseService(
3839 EntityIconService entityIconService ,
3940 RecordMappingService recordMappingService ,
4041 SolutionComponentService solutionComponentService ,
42+ SolutionComponentExtractor solutionComponentExtractor ,
4143 WorkflowService workflowService ,
4244 RelationshipService relationshipService )
4345 {
@@ -49,6 +51,7 @@ public DataverseService(
4951 this . recordMappingService = recordMappingService ;
5052 this . workflowService = workflowService ;
5153 this . relationshipService = relationshipService ;
54+ this . solutionComponentExtractor = solutionComponentExtractor ;
5255
5356 // Register all analyzers with their query functions
5457 analyzerRegistrations = new List < IAnalyzerRegistration >
@@ -69,7 +72,7 @@ public DataverseService(
6972 this . solutionComponentService = solutionComponentService ;
7073 }
7174
72- public async Task < ( IEnumerable < Record > , IEnumerable < SolutionWarning > ) > GetFilteredMetadata ( )
75+ public async Task < ( IEnumerable < Record > , IEnumerable < SolutionWarning > , IEnumerable < SolutionComponentCollection > ) > GetFilteredMetadata ( )
7376 {
7477 // used to collect warnings for the insights dashboard
7578 var warnings = new List < SolutionWarning > ( ) ;
@@ -275,8 +278,79 @@ public DataverseService(
275278 } )
276279 . ToList ( ) ;
277280
278- logger . LogInformation ( $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] GetFilteredMetadata completed - returning empty results") ;
279- return ( records , warnings ) ;
281+ /// SOLUTION COMPONENTS FOR INSIGHTS
282+ List < SolutionComponentCollection > solutionComponentCollections ;
283+ try
284+ {
285+ logger . LogInformation ( $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] Extracting solution components for insights view") ;
286+
287+ // Build name lookups from entity metadata for the extractor
288+ var entityNameLookup = entitiesInSolutionMetadata . ToDictionary (
289+ e => e . MetadataId ! . Value ,
290+ e => e . DisplayName . ToLabelString ( ) ?? e . SchemaName ) ;
291+
292+ var attributeNameLookup = entitiesInSolutionMetadata
293+ . SelectMany ( e => e . Attributes . Where ( a => a . MetadataId . HasValue ) )
294+ . ToDictionary (
295+ a => a . MetadataId ! . Value ,
296+ a => a . DisplayName . ToLabelString ( ) ?? a . SchemaName ) ;
297+
298+ var relationshipNameLookup = entitiesInSolutionMetadata
299+ . SelectMany ( e => e . ManyToManyRelationships . Cast < RelationshipMetadataBase > ( )
300+ . Concat ( e . OneToManyRelationships )
301+ . Concat ( e . ManyToOneRelationships ) )
302+ . Where ( r => r . MetadataId . HasValue )
303+ . DistinctBy ( r => r . MetadataId ! . Value )
304+ . ToDictionary (
305+ r => r . MetadataId ! . Value ,
306+ r => r . SchemaName ) ;
307+
308+ // Build entity lookups for attributes, relationships, and keys (maps component ID to parent entity name)
309+ var attributeEntityLookup = entitiesInSolutionMetadata
310+ . SelectMany ( e => e . Attributes . Where ( a => a . MetadataId . HasValue )
311+ . Select ( a => ( AttributeId : a . MetadataId ! . Value , EntityName : e . DisplayName . ToLabelString ( ) ?? e . LogicalName ) ) )
312+ . ToDictionary ( x => x . AttributeId , x => x . EntityName ) ;
313+
314+ var relationshipEntityLookup = entitiesInSolutionMetadata
315+ . SelectMany ( e => e . ManyToManyRelationships . Cast < RelationshipMetadataBase > ( )
316+ . Concat ( e . OneToManyRelationships )
317+ . Concat ( e . ManyToOneRelationships )
318+ . Where ( r => r . MetadataId . HasValue )
319+ . Select ( r => ( RelationshipId : r . MetadataId ! . Value , EntityName : e . DisplayName . ToLabelString ( ) ?? e . LogicalName ) ) )
320+ . DistinctBy ( x => x . RelationshipId )
321+ . ToDictionary ( x => x . RelationshipId , x => x . EntityName ) ;
322+
323+ var keyEntityLookup = entitiesInSolutionMetadata
324+ . SelectMany ( e => ( e . Keys ?? Array . Empty < EntityKeyMetadata > ( ) )
325+ . Where ( k => k . MetadataId . HasValue )
326+ . Select ( k => ( KeyId : k . MetadataId ! . Value , EntityName : e . DisplayName . ToLabelString ( ) ?? e . LogicalName ) ) )
327+ . ToDictionary ( x => x . KeyId , x => x . EntityName ) ;
328+
329+ // Build solution name lookup
330+ var solutionNameLookup = solutionLookup . ToDictionary (
331+ kvp => kvp . Key ,
332+ kvp => kvp . Value . Name ) ;
333+
334+ solutionComponentCollections = await solutionComponentExtractor . ExtractSolutionComponentsAsync (
335+ solutionIds ,
336+ solutionNameLookup ,
337+ entityNameLookup ,
338+ attributeNameLookup ,
339+ relationshipNameLookup ,
340+ attributeEntityLookup ,
341+ relationshipEntityLookup ,
342+ keyEntityLookup ) ;
343+
344+ logger . LogInformation ( $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] Extracted components for { solutionComponentCollections . Count } solutions") ;
345+ }
346+ catch ( Exception ex )
347+ {
348+ logger . LogWarning ( ex , $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] Failed to extract solution components for insights, continuing without them") ;
349+ solutionComponentCollections = new List < SolutionComponentCollection > ( ) ;
350+ }
351+
352+ logger . LogInformation ( $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] GetFilteredMetadata completed") ;
353+ return ( records , warnings , solutionComponentCollections ) ;
280354 }
281355 }
282356
0 commit comments