3. Data Models & DTOs

  1. Data Models & DTOs

3.1 Creating Domain Models

namespace CommandAPI.Models;public class Platform{    [Key]    public int Id { get; set; }    [Required]    public required string PlatformName { get; set; }    // Navigation property    public ICollection Commands { get; set; } = new List();    public string? CreatedBy { get; set; }} Required Members (C# 11+): required keyword enforces initialization Nullable Reference Types: string? vs string Navigation Properties: EF Core uses these for relationships Collection Initialization: Best practice to avoid null reference issues 3.2 Understanding DTOs and Why We Need Them DTO = Data Transfer Object: Contracts for API communication Why Not Expose Models Directly?: Security: Hide sensitive fields (passwords, internal IDs) Versioning: API contract independent of database schema Over-posting: Prevent clients from setting unauthorized fields Performance: Return only needed data Circular References: Avoid JSON serialization issues 3.3 CORRECTION: Proper C# Naming Conventions

// ❌ WRONG (current code has this issue)public class AppDbContext : DbContext{    public DbSet platforms { get; set; }  // camelCase    public DbSet commands { get; set; }}// ✅ CORRECTpublic class AppDbContext : DbContext{    public DbSet Platforms { get; set; }  // PascalCase    public DbSet Commands { get; set; }    public DbSet KeyRegistrations { get; set; }    public DbSet BulkJobResults { get; set; }} C# Naming Conventions: Classes, Properties, Methods: PascalCase Local variables, parameters: camelCase Private fields: _camelCase (with underscore) Constants: UPPER_SNAKE_CASE or PascalCase 3.4 Data Annotations for Basic Validation

public class PlatformMutateDto{    [Required(ErrorMessage = “Platform name is required”)]    [MaxLength(100, ErrorMessage = “Platform name cannot exceed 100 characters”)]    [MinLength(2, ErrorMessage = “Platform name must be at least 2 characters”)]    public required string PlatformName { get; init; }}public class CommandMutateDto{    [Required]    [MaxLength(250)]    public required string HowTo { get; init; }    [Required]    public required string CommandLine { get; init; }    [Range(1, int.MaxValue, ErrorMessage = “Valid Platform ID required”)]    public int PlatformId { get; set; }} Common Annotations: [Required] - non-null, non-empty [MaxLength(n)] - string/array length [Range(min, max)] - numeric bounds [EmailAddress], [Url], [Phone] - format validation [RegularExpression(pattern)] - custom patterns 3.5 The Separation of Concerns Principle

┌─────────────────┐     ┌──────────────┐     ┌────────────────┐│   Controller    │────▶│  Repository  │────▶│   DbContext    ││  (HTTP Logic)   │     │ (Data Logic) │     │  (EF Core)     │└─────────────────┘     └──────────────┘     └────────────────┘        │                                              │        ▼                                              ▼   ┌─────────┐                                  ┌──────────┐   │   DTO   │                                  │  Models  │   └─────────┘                                  └──────────┘        │                                              │        └────────────────┬─────────────────────────────┘                         ▼                   ┌────────────┐                   │ AutoMapper │                   └────────────┘ Layers Explained: Controller: Handles HTTP, validates input, returns responses Repository: Data access logic, queries, business rules DbContext: EF Core abstraction over database Models: Database entities DTOs: API contracts AutoMapper: Transforms between Models and DTOs