Dynamic & Extensible Systems Documentation
Overview
To ensure maximum future-proofing, the system includes several dynamic and extensible mechanisms that allow adding new properties, categories, and relationships without schema changes.
Dynamic Systems
1. LookupTable - Dynamic Categories/Types
Purpose: Replace hard-coded enums with database-driven lookup tables that can be extended by users or administrators.
Benefits:
- Add new values without code changes
- User-defined categories
- Hierarchical categories (parent-child)
- Metadata for each value
- Usage tracking
Example Usage:
// Instead of hard-coded enum, use lookup table
var customPower = new LookupTable
{
Category = "RodPower",
Name = "Extra Ultra Light",
Code = "ExtraUltraLight",
IsSystemDefined = false, // User-defined
DisplayOrder = 0
};
// Entities can use both enum (for type safety) AND lookup (for extensibility)
rodBlank.Power = RodPower.UltraLight; // Standard enum
rodBlank.PowerLookupId = customPower.Id; // Custom value
Categories:
- RodPower, RodAction, RodMaterial
- GuideType, GuideFrameType, GuideRingType
- WrapType, WrapPattern
- FinishType, FinishGloss
- KnotCategory, KnotDifficulty
- PressureTrend, PrecipitationType, CloudCoverType
- TideType, TideRangeType
- And any future categories
2. EntityAttribute - Generic Attribute System
Purpose: Add custom attributes to any entity without schema changes.
Benefits:
- No schema changes needed
- Support for multiple value types (string, number, boolean, DateTime, JSON)
- Unit support (cm, kg, mph, etc.)
- Lookup references for standardized values
Example Usage:
// Add custom attribute to a rod
var customAttr = new EntityAttribute
{
EntityType = "Rod",
EntityGuidId = rod.Id,
AttributeKey = "CustomActionRating",
NumericValue = 8.5m,
Unit = "out of 10",
AttributeType = AttributeType.Number,
IsUserDefined = true
};
// Add JSON attribute for complex data
var jsonAttr = new EntityAttribute
{
EntityType = "RodBuild",
EntityIntId = rodBuild.Id,
AttributeKey = "CustomBuildSpecs",
JsonValue = JsonSerializer.Serialize(new {
CustomGuideSpacing = "Progressive",
SpecialWraps = new[] { "Diamond", "Chevron" }
}),
AttributeType = AttributeType.Json
};
3. EntityTag - Generic Tagging System
Purpose: Tag any entity with normalized tags, more flexible than entity-specific tag relationships.
Benefits:
- Works with any entity type
- Uses normalized Tag entity
- Context-aware (Category, UseCase, Condition, etc.)
- No need for entity-specific tag relationships
Example Usage:
// Tag a rod with multiple contexts
var tag1 = new EntityTag
{
EntityType = "Rod",
EntityGuidId = rod.Id,
TagId = trollingTag.Id,
Context = "UseCase"
};
var tag2 = new EntityTag
{
EntityType = "Rod",
EntityGuidId = rod.Id,
TagId = saltwaterTag.Id,
Context = "WaterType"
};
4. EntityMetadata - JSON Metadata Storage
Purpose: Store extensible JSON data for any entity without schema changes.
Benefits:
- Store complex nested data
- Schema versioning support
- Multiple metadata keys per entity
- No schema changes needed
Example Usage:
// Store extended weather data
var metadata = new EntityMetadata
{
EntityType = "LocationWeatherHistory",
EntityIntId = weather.Id,
MetadataKey = "ExtendedWeatherData",
SchemaVersion = "1.0",
SchemaType = "ExtendedWeather",
JsonData = JsonSerializer.Serialize(new {
AirQuality = new { AQI = 45, PM25 = 12.5 },
UVIndex = 6,
SolarRadiation = 850,
CustomFields = new Dictionary<string, object>()
})
};
5. EntityRelationship - Generic Relationship System
Purpose: Create relationships between any entities without hard-coded foreign keys.
Benefits:
- Dynamic relationships
- Relationship types (RelatedTo, SimilarTo, Replaces, etc.)
- Relationship strength/confidence
- Bidirectional support
- Metadata for relationship details
Example Usage:
// Relate two rods
var relationship = new EntityRelationship
{
SourceEntityType = "Rod",
SourceEntityGuidId = rod1.Id,
TargetEntityType = "Rod",
TargetEntityGuidId = rod2.Id,
RelationshipType = "SimilarTo",
Strength = 0.85f,
Notes = "Similar action and power"
};
// Relate gear items
var gearRel = new EntityRelationship
{
SourceEntityType = "Lure",
SourceEntityGuidId = lure1.Id,
TargetEntityType = "Lure",
TargetEntityGuidId = lure2.Id,
RelationshipType = "VariantOf",
Notes = "Color variant"
};
Hybrid Approach: Enums + Lookup Tables
For maximum flexibility, many entities support both enums (for type safety) and lookup tables (for extensibility):
public class RodBlank
{
// Enum for type safety and standard values
public RodPower Power { get; set; }
// Lookup table for custom/extended values
public int? PowerLookupId { get; set; }
public LookupTable? PowerLookup { get; set; }
}
Benefits:
- Type safety for standard values (enums)
- Extensibility for custom values (lookup tables)
- Best of both worlds
Migration Strategy
Phase 1: Use Enums (Current)
- Enums provide type safety
- Standard values are well-defined
- Easy to use in code
Phase 2: Add Lookup Tables (Future)
- Seed lookup tables with enum values
- Add optional lookup table references to entities
- Maintain backward compatibility
Phase 3: Full Dynamic (Future)
- Migrate to lookup tables for user-defined values
- Keep enums for system-defined values
- Use EntityAttribute for completely custom properties
Best Practices
- Use Enums for Standard Values: Keep enums for well-defined, stable categories
- Use Lookup Tables for Extensible Values: Use lookup tables for categories that may grow
- Use EntityAttribute for Custom Properties: Use attributes for entity-specific custom fields
- Use EntityMetadata for Complex Data: Use metadata for nested/complex data structures
- Use EntityTag for Flexible Categorization: Use tags for multi-dimensional categorization
- Use EntityRelationship for Dynamic Links: Use relationships for flexible entity connections
Examples
Adding Custom Rod Power
// 1. Create lookup table entry
var customPower = new LookupTable
{
Category = "RodPower",
Name = "Super Heavy",
Code = "SuperHeavy",
IsSystemDefined = false,
DisplayOrder = 8
};
// 2. Use in rod blank
rodBlank.Power = RodPower.UltraHeavy; // Closest enum
rodBlank.PowerLookupId = customPower.Id; // Custom value
Adding Custom Weather Property
// Add custom weather attribute
var customWeather = new EntityAttribute
{
EntityType = "LocationWeatherHistory",
EntityIntId = weather.Id,
AttributeKey = "SolarRadiation",
NumericValue = 850m,
Unit = "W/m²",
AttributeType = AttributeType.Number
};
Storing Complex Build Data
// Store complex rod build metadata
var buildMetadata = new EntityMetadata
{
EntityType = "RodBuild",
EntityIntId = rodBuild.Id,
MetadataKey = "BuildProcess",
JsonData = JsonSerializer.Serialize(new {
Steps = new[] {
new { Step = "Guide Placement", Time = "2 hours" },
new { Step = "Wrapping", Time = "4 hours" },
new { Step = "Finishing", Time = "1 hour" }
},
ToolsUsed = new[] { "Power Wrapper", "Finish Turner" },
CustomNotes = "Used custom guide spacing formula"
})
};
Future Enhancements
- UI for Managing Lookup Tables: Admin interface for managing categories
- User-Defined Categories: Allow users to create their own categories
- Category Templates: Pre-defined category sets for common use cases
- Attribute Schemas: Define schemas for EntityAttribute values
- Relationship Validation: Validate relationship types and entities
- Metadata Schemas: Versioned schemas for EntityMetadata JSON data