in doc-architect/doc-architect-core/src/main/java/com/docarchitect/core/scanner/impl/dotnet/EntityFrameworkScanner.java [178:270]
public ScanResult scan(ScanContext context) {
log.info("Scanning Entity Framework entities in: {}", context.rootPath());
List<DataEntity> dataEntities = new ArrayList<>();
List<Relationship> relationships = new ArrayList<>();
Set<String> entityNames = new HashSet<>();
Map<String, String> baseClassMap = new HashMap<>(); // Maps entity name to base class name
ScanStatistics.Builder statsBuilder = new ScanStatistics.Builder();
List<Path> csFiles = context.findFiles(CS_FILE_PATTERN).toList();
statsBuilder.filesDiscovered(csFiles.size());
if (csFiles.isEmpty()) {
return emptyResult();
}
// First pass: Find DbContext and collect entity names from DbSet properties
for (Path csFile : csFiles) {
try {
collectEntityNamesFromDbContext(csFile, entityNames);
} catch (Exception e) {
log.warn("Failed to parse DbContext file: {} - {}", csFile, e.getMessage());
}
}
// Second pass: Find entities from OnModelCreating Fluent API
for (Path csFile : csFiles) {
try {
collectEntityNamesFromFluentApi(csFile, entityNames);
} catch (Exception e) {
log.warn("Failed to parse Fluent API in file: {} - {}", csFile, e.getMessage());
}
}
// Third pass: Build inheritance map for all classes (using AST)
for (Path csFile : csFiles) {
try {
buildInheritanceMap(csFile, baseClassMap);
} catch (Exception e) {
log.warn("Failed to build inheritance map from file: {} - {}", csFile, e.getMessage());
}
}
// Fourth pass: Detect entities through inheritance (e.g., classes inheriting from BaseEntity)
for (Path csFile : csFiles) {
try {
collectEntityNamesFromInheritance(csFile, entityNames, baseClassMap);
} catch (Exception e) {
log.warn("Failed to detect entities by inheritance in file: {} - {}", csFile, e.getMessage());
}
}
log.debug("Discovered {} potential entity types", entityNames.size());
// Final pass: Parse entity classes with three-tier fallback
for (Path csFile : csFiles) {
if (!shouldScanFile(csFile)) {
continue;
}
statsBuilder.incrementFilesScanned();
// Use three-tier parsing with fallback
FileParseResult<EntityResult> result = parseWithFallback(
csFile,
classes -> extractEntitiesFromAST(classes, entityNames),
createFallbackStrategy(entityNames),
statsBuilder
);
if (result.isSuccess()) {
for (EntityResult entityResult : result.getData()) {
dataEntities.add(entityResult.entity());
relationships.addAll(entityResult.relationships());
}
}
}
ScanStatistics statistics = statsBuilder.build();
log.info("Found {} Entity Framework entities and {} relationships (success rate: {:.1f}%, overall parse rate: {:.1f}%)",
dataEntities.size(), relationships.size(), statistics.getSuccessRate(), statistics.getOverallParseRate());
return buildSuccessResult(
List.of(),
List.of(),
List.of(),
List.of(),
dataEntities,
relationships,
List.of(),
statistics
);
}