Entity Framework Core Mastery

Value Conversions (Enums & Strongly Typed IDs)

1 Views Updated 5/4/2026

Value Conversions (Enums & Strongly Typed IDs)

Sometimes, the data type we want to use in C# memory (like a rich object or an Enum) cannot be natively stored in a SQL database column. Value Conversions act as microscopic translators that run automatically, converting complex C# types into simple SQL types upon saving, and reversing the process upon loading.

1. Storing Enums as Strings

By default, EF Core stores C# Enums in SQL Server as Integers (e.g., 0, 1, 2). This is a nightmare for DBAs trying to read the raw database because "Status = 2" is meaningless without reading the C# source code. We can force EF Core to store the Enum as a String!

public enum OrderStatus { Pending, Shipped, Delivered }

public class Order
{
    public int Id { get; set; }
    public OrderStatus Status { get; set; }
}

// In OnModelCreating:
modelBuilder.Entity<Order>()
            .Property(o => o.Status)
            // C# -> SQL, SQL -> C#
            .HasConversion(
                v => v.ToString(), // How to save to SQL ("Pending")
                v => (OrderStatus)Enum.Parse(typeof(OrderStatus), v)); // How to load back to C#

2. Storing Complex Value Objects (JSON)

What if you have a C# object representing an "Address" with a Street, City, and Zip code, but you just want to store the entire thing flat inside a single SQL 'NVARCHAR' column?

public class Address { public string City; public string Zip; }

modelBuilder.Entity<User>()
    .Property(u => u.HomeAddress)
    .HasConversion(
        addressObj => JsonSerializer.Serialize(addressObj, (JsonSerializerOptions)null),
        jsonString => JsonSerializer.Deserialize<Address>(jsonString, (JsonSerializerOptions)null)
    );

3. Strongly Typed IDs (Domain Driven Design)

A massive bug in C# is passing a ProductId integer into a method that expects a UserId integer. The compiler won't complain because they are both integers. DDD solves this by creating strict ProductId and UserId records. We use Value Conversions to teach EF Core how to handle these custom types.

// The Strongly Typed Record
public readonly record struct ProductId(int Value);

public class Product
{
    public ProductId Id { get; set; } // It is absolutely IMPOSSIBLE to assign a UserId here!
}

// Teaching EF Core how to save this custom record as a normal integer
modelBuilder.Entity<Product>()
            .Property(p => p.Id)
            .HasConversion(
                id => id.Value,           // Extract the raw int for SQL Server
                value => new ProductId(value) // Wrap the int back into the Record on load
            );

4. Interview Mastery

Q: "If we use a Value Conversion to store a complex object as JSON in an `NVARCHAR(MAX)` column, can we still use EF Core LINQ to filter the data, such as `.Where(u => u.HomeAddress.City == 'London')`?"

Architect Answer: "No, you absolutely cannot. This is the primary pitfall of Value Conversions. Value Conversions operate purely in .NET Memory as a translation layer. SQL Server has no idea what 'HomeAddress.City' means because it just sees a giant string blob. When EF Core tries to translate the LINQ `Where` clause into SQL, it will throw a severe `InvalidOperationException` because it cannot map the JSON property to a SQL Column. If you need to physically query data using LINQ, you must use Owned Entities (which map to physical columns) or EF Core 7+'s native JSON column mapping capabilities, rather than a hacky string-based Value Conversion."

Entity Framework Core Mastery
1. Foundations & Architecture
Introduction to Object Relational Mapping (ORM) Entity Framework Core Architecture & Providers Setup and DbContext Integration Code-First vs Database-First Approaches Reverse Engineering Existing Databases (Scaffolding)
2. Code-First Modeling
Entity Conventions & Data Annotations The Fluent API Deep Dive (OnModelCreating) Primary Keys, Composite Keys, & Guids Required Properties & Database Defaults Value Conversions (Enums & Strongly Typed IDs)
3. Relational Architecture
One-to-Many Relationships & Foreign Keys One-to-One Relationships (Dependent Entities) Many-to-Many Relationships & Navigation Properties Owned Entity Types (Value Objects) Table-per-Hierarchy (TPH) Inheritance
4. Data Querying & LINQ
Basic LINQ Queries & IQueryable Execution Tracking vs No-Tracking Queries (Performance) Eager Loading vs Explicit Loading (Include) Lazy Loading Pitfalls & Proxies Client vs Server Evaluation Parsing
5. Manipulating Data (CUD)
Adding, Updating, and Removing Entities The ChangeTracker and Entity States Disconnected Entities in Web APIs Batch Updates and Deletes (.NET 7+)
6. Advanced Performance & Scale
Concurrency Tokens and Optimistic Locking Raw SQL Queries and Views (FromSqlRaw) Compiled Queries for High Throughput Interceptors (Logging & Auditing Data Changes) DbContext Pooling Mechanisms Managing Complex EF Core Migrations (CI/CD)