Handling Partial Updates with
Nullable Fields in .NET Core
Architecture Discussion – PATCH
/Opportunity
The Problem
• PATCH /Opportunity updates multiple fields
like stage_id, budget, etc.
• Using nullable DTOs introduces ambiguity:
• - Is `null` an intentional update or field
omission?
• - We can't distinguish between 'not passed' vs
'set null'
What We Want
• We need to distinguish three scenarios:
• 1. Omitted field → Don't update
• 2. Field set to a value → Update
• 3. Field explicitly null → Unset (set to null)
Approach 1 – PatchableValue<T>
• Custom wrapper type with IsSet flag.
• Pros:
• - Strongly typed
• - No ambiguity
• - Reusable for all types
• Cons:
• - Requires custom converter
PatchableValue Example
• public struct PatchableValue<T>
• {
• public T? Value { get; }
• public bool IsSet { get; }
• public PatchableValue(T? value) { Value =
value; IsSet = true; }
• public static readonly PatchableValue<T>
Unset = default;
• }
Approach 2 – Use string in DTO
• All fields are strings in DTO. Parsed in
application layer.
• Pros:
• - Simple, no converters
• - Clean DTOs
• - Easy for frontend
• Cons:
String DTO Example
• DTO:
• public string? StageId { get; set; }
• Logic:
• if (dto.StageId == "") → Set null
• if (dto.StageId != null) → Parse and set
• if (dto.StageId == null) → Don't update
Comparison
• PatchableValue<T>
• + Strongly typed
• + Robust handling
• - More boilerplate
• string approach
• + Simple and lean
• + Easier for frontend
• - Weaker type safety
Recommendation
• Use PatchableValue<T> for complex, scalable
needs.
• Use string-in-DTO for simple APIs or rapid
delivery.
• Standardize one approach across PATCH
endpoints.
Next Steps
• Choose one approach as standard
• Refactor existing PATCH DTOs
• Add helper methods for consistency
• Document frontend integration strategy

PartialUpdate_Strategies_Presentation.pptx

  • 1.
    Handling Partial Updateswith Nullable Fields in .NET Core Architecture Discussion – PATCH /Opportunity
  • 2.
    The Problem • PATCH/Opportunity updates multiple fields like stage_id, budget, etc. • Using nullable DTOs introduces ambiguity: • - Is `null` an intentional update or field omission? • - We can't distinguish between 'not passed' vs 'set null'
  • 3.
    What We Want •We need to distinguish three scenarios: • 1. Omitted field → Don't update • 2. Field set to a value → Update • 3. Field explicitly null → Unset (set to null)
  • 4.
    Approach 1 –PatchableValue<T> • Custom wrapper type with IsSet flag. • Pros: • - Strongly typed • - No ambiguity • - Reusable for all types • Cons: • - Requires custom converter
  • 5.
    PatchableValue Example • publicstruct PatchableValue<T> • { • public T? Value { get; } • public bool IsSet { get; } • public PatchableValue(T? value) { Value = value; IsSet = true; } • public static readonly PatchableValue<T> Unset = default; • }
  • 6.
    Approach 2 –Use string in DTO • All fields are strings in DTO. Parsed in application layer. • Pros: • - Simple, no converters • - Clean DTOs • - Easy for frontend • Cons:
  • 7.
    String DTO Example •DTO: • public string? StageId { get; set; } • Logic: • if (dto.StageId == "") → Set null • if (dto.StageId != null) → Parse and set • if (dto.StageId == null) → Don't update
  • 8.
    Comparison • PatchableValue<T> • +Strongly typed • + Robust handling • - More boilerplate • string approach • + Simple and lean • + Easier for frontend • - Weaker type safety
  • 9.
    Recommendation • Use PatchableValue<T>for complex, scalable needs. • Use string-in-DTO for simple APIs or rapid delivery. • Standardize one approach across PATCH endpoints.
  • 10.
    Next Steps • Chooseone approach as standard • Refactor existing PATCH DTOs • Add helper methods for consistency • Document frontend integration strategy