@@ -375,10 +375,171 @@ private void SetOrganizationId(TEntity entity, Guid organizationId)
375375 /// </summary>
376376 protected virtual async Task < TEntity > SetCreateDefaultsAsync ( TEntity entity )
377377 {
378+ // Automatically propagate IsSampleData flag from parent entities
379+ await InheritSampleDataFlagFromParentsAsync ( entity ) ;
380+
378381 await Task . CompletedTask ;
379382 return entity ;
380383 }
381384
385+ /// <summary>
386+ /// Checks parent entities for IsSampleData flag and propagates to child entity.
387+ /// If any parent entity has IsSampleData = true, the child entity is marked as sample data.
388+ /// This ensures sample data "taints" all related records for proper cleanup.
389+ /// </summary>
390+ /// <param name="entity">The entity being created</param>
391+ /// <returns>Task</returns>
392+ protected virtual async Task InheritSampleDataFlagFromParentsAsync ( TEntity entity )
393+ {
394+ try
395+ {
396+ // If already marked as sample data, no need to check parents
397+ if ( entity . IsSampleData )
398+ {
399+ return ;
400+ }
401+
402+ // Check for common parent relationship properties
403+ var entityType = typeof ( TEntity ) ;
404+ var properties = entityType . GetProperties ( ) ;
405+
406+ // Common parent ID properties to check
407+ var parentIdProperties = new [ ]
408+ {
409+ "PropertyId" ,
410+ "LeaseId" ,
411+ "InvoiceId" ,
412+ "TenantId" ,
413+ "ProspectiveTenantId" ,
414+ "RentalApplicationId" ,
415+ "RepairId" ,
416+ "InspectionId" ,
417+ "MaintenanceRequestId" ,
418+ "OrganizationId" // Check organization itself for multi-tenant sample orgs
419+ } ;
420+
421+ foreach ( var parentPropName in parentIdProperties )
422+ {
423+ var parentIdProperty = properties . FirstOrDefault ( p =>
424+ p . Name == parentPropName &&
425+ ( p . PropertyType == typeof ( Guid ) || p . PropertyType == typeof ( Guid ? ) ) ) ;
426+
427+ if ( parentIdProperty == null ) continue ;
428+
429+ var parentId = parentIdProperty . GetValue ( entity ) ;
430+ if ( parentId == null || ( parentId is Guid guidValue && guidValue == Guid . Empty ) ) continue ;
431+
432+ // Determine parent entity type and check IsSampleData flag
433+ bool parentIsSampleData = await CheckParentEntityIsSampleDataAsync ( parentPropName , ( Guid ) parentId ) ;
434+
435+ if ( parentIsSampleData )
436+ {
437+ entity . IsSampleData = true ;
438+ _logger . LogInformation (
439+ $ "{ typeof ( TEntity ) . Name } marked as sample data - inherited from { parentPropName } ({ parentId } )") ;
440+ return ; // Once marked as sample data, no need to check other parents
441+ }
442+ }
443+ }
444+ catch ( Exception ex )
445+ {
446+ // Log but don't fail entity creation if sample data check fails
447+ _logger . LogWarning ( ex , $ "Error checking parent sample data flag for { typeof ( TEntity ) . Name } ") ;
448+ }
449+ }
450+
451+ /// <summary>
452+ /// Checks if a parent entity has IsSampleData = true.
453+ /// Simple direct query approach for better reliability and maintainability.
454+ /// </summary>
455+ /// <param name="parentPropertyName">Parent property name (e.g., "LeaseId", "PropertyId")</param>
456+ /// <param name="parentId">Parent entity ID</param>
457+ /// <returns>True if parent is sample data, false otherwise</returns>
458+ private async Task < bool > CheckParentEntityIsSampleDataAsync ( string parentPropertyName , Guid parentId )
459+ {
460+ try
461+ {
462+ // Direct queries for each entity type - simple and reliable
463+ switch ( parentPropertyName )
464+ {
465+ case "PropertyId" :
466+ var property = await _context . Properties
467+ . Where ( p => p . Id == parentId )
468+ . Select ( p => p . IsSampleData )
469+ . FirstOrDefaultAsync ( ) ;
470+ return property ;
471+
472+ case "LeaseId" :
473+ var lease = await _context . Leases
474+ . Where ( l => l . Id == parentId )
475+ . Select ( l => l . IsSampleData )
476+ . FirstOrDefaultAsync ( ) ;
477+ return lease ;
478+
479+ case "InvoiceId" :
480+ var invoice = await _context . Invoices
481+ . Where ( i => i . Id == parentId )
482+ . Select ( i => i . IsSampleData )
483+ . FirstOrDefaultAsync ( ) ;
484+ return invoice ;
485+
486+ case "TenantId" :
487+ var tenant = await _context . Tenants
488+ . Where ( t => t . Id == parentId )
489+ . Select ( t => t . IsSampleData )
490+ . FirstOrDefaultAsync ( ) ;
491+ return tenant ;
492+
493+ case "ProspectiveTenantId" :
494+ var prospect = await _context . ProspectiveTenants
495+ . Where ( pt => pt . Id == parentId )
496+ . Select ( pt => pt . IsSampleData )
497+ . FirstOrDefaultAsync ( ) ;
498+ return prospect ;
499+
500+ case "RentalApplicationId" :
501+ var application = await _context . RentalApplications
502+ . Where ( ra => ra . Id == parentId )
503+ . Select ( ra => ra . IsSampleData )
504+ . FirstOrDefaultAsync ( ) ;
505+ return application ;
506+
507+ case "RepairId" :
508+ var repair = await _context . Repairs
509+ . Where ( r => r . Id == parentId )
510+ . Select ( r => r . IsSampleData )
511+ . FirstOrDefaultAsync ( ) ;
512+ return repair ;
513+
514+ case "InspectionId" :
515+ var inspection = await _context . Inspections
516+ . Where ( i => i . Id == parentId )
517+ . Select ( i => i . IsSampleData )
518+ . FirstOrDefaultAsync ( ) ;
519+ return inspection ;
520+
521+ case "MaintenanceRequestId" :
522+ var maintenanceRequest = await _context . MaintenanceRequests
523+ . Where ( mr => mr . Id == parentId )
524+ . Select ( mr => mr . IsSampleData )
525+ . FirstOrDefaultAsync ( ) ;
526+ return maintenanceRequest ;
527+
528+ // OrganizationId is NOT checked - Organizations don't have IsSampleData flag
529+ // Sample data is marked at the entity level within an organization
530+
531+ default :
532+ _logger . LogDebug ( $ "Unknown parent property: { parentPropertyName } ") ;
533+ return false ;
534+ }
535+ }
536+ catch ( Exception ex )
537+ {
538+ _logger . LogDebug ( ex , $ "Could not check IsSampleData for { parentPropertyName } ") ;
539+ return false ;
540+ }
541+ }
542+
382543 /// <summary>
383544 /// Hook method called after creating entity for post-creation operations.
384545 /// Override in derived services to handle side effects like updating related entities.
0 commit comments