C# tutorials > Frameworks and Libraries > Entity Framework Core (EF Core) > What are value converters?
What are value converters?
Value converters in Entity Framework Core (EF Core) are a powerful mechanism for translating property values between your .NET entities and the database columns they map to. This allows you to handle scenarios where the data representation in your application domain doesn't directly match the data representation in your database. They provide a clean and centralized way to manage these transformations, keeping your entity classes cleaner and more focused on business logic.
Introduction to Value Converters
EF Core uses value converters to handle data type differences between .NET properties and database columns. For instance, you might want to store an enumeration as a string in the database or encrypt sensitive data before saving it. Value converters bridge this gap by defining how a .NET value is converted to a database value and vice versa.
Basic Value Converter Example: Storing Enums as Strings
This example demonstrates converting a C# enum Status
to a string in the database. The HasConversion
method takes two lambda expressions:
v => v.ToString()
converts the enum value to its string representation before saving it to the database.v => (Status)Enum.Parse(typeof(Status), v)
converts the string value read from the database back to the corresponding enum value.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
public enum Status { Active, Inactive, Pending }
public class MyEntity
{
public int Id { get; set; }
public Status EntityStatus { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>()
.Property(e => e.EntityStatus)
.HasConversion(
v => v.ToString(),
v => (Status)Enum.Parse(typeof(Status), v));
}
}
Concepts Behind the Snippet
The core idea is that the HasConversion
method configures a ValueConverter
for a specific property. This converter encapsulates the logic for both inbound (database to .NET) and outbound (.NET to database) transformations. EF Core automatically applies this converter whenever it interacts with this property.
Real-Life Use Case: Storing Booleans as Integers
Some databases might not have a native boolean type. In this case, you can store boolean values as integers (0 or 1). The ValueConverter
handles the conversion between the .NET bool
and the integer value in the database. This is particularly useful when working with legacy databases or systems where you don't have control over the database schema.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
public class UserSettings
{
public int Id { get; set; }
public bool IsActive { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<UserSettings> UserSettings { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserSettings>()
.Property(e => e.IsActive)
.HasConversion(
v => v ? 1 : 0,
v => v == 1);
}
}
Advanced Value Converter: Encrypting Data
This advanced example demonstrates encrypting data before storing it in the database. A custom EncryptionConverter
class inherits from ValueConverter<string, string>
and handles the encryption and decryption logic. Important: This example uses AES encryption with a hardcoded key for simplicity. In a real-world application, you should use a more secure key management strategy (e.g., storing the key in a secure configuration file, Azure Key Vault, or a hardware security module (HSM)). Also, handle the IV more carefully.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System.Security.Cryptography;
using System.Text;
public class SensitiveData
{
public int Id { get; set; }
public string EncryptedValue { get; set; }
}
public class EncryptionConverter : ValueConverter<string, string>
{
private readonly string _encryptionKey = "YourSuperSecretKey"; // Never hardcode in prod!
public EncryptionConverter()
: base(
v => Encrypt(v, _encryptionKey),
v => Decrypt(v, _encryptionKey))
{
}
private static string Encrypt(string data, string key)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.UTF8.GetBytes(key);
aesAlg.IV = new byte[16]; // Initialization Vector (IV) - important for security
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(data);
}
return Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
private static string Decrypt(string data, string key)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.UTF8.GetBytes(key);
aesAlg.IV = new byte[16];
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(data)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
}
public class MyDbContext : DbContext
{
public DbSet<SensitiveData> SensitiveData { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var encryptionConverter = new EncryptionConverter();
modelBuilder.Entity<SensitiveData>()
.Property(e => e.EncryptedValue)
.HasConversion(encryptionConverter);
}
}
Best Practices
Interview Tip
When discussing value converters in an interview, emphasize their role in decoupling your domain model from the database schema. Explain how they promote code reusability and maintainability by centralizing data transformation logic. Also, be prepared to discuss different use cases, such as enum conversions, boolean representations, and data encryption.
When to Use Them
Memory Footprint
Value converters generally don't introduce a significant memory overhead. The memory footprint is primarily determined by the data being converted and the complexity of the conversion logic. Simple conversions (e.g., enum to string) will have a minimal impact. More complex conversions (e.g., encryption) might require more memory due to temporary buffers and cryptographic operations.
Alternatives
Pros
Cons
FAQ
-
Can I use value converters with LINQ queries?
Yes, value converters work seamlessly with LINQ queries. EF Core automatically applies the converters when translating LINQ queries to SQL queries.
-
How do I register a value converter globally for all properties of a specific type?
You can register a value converter globally by using the
ModelBuilder.Types<T>().Configure(b => b.Property(p => p).HasConversion(...))
method in yourOnModelCreating
method. -
Are value converters applied when loading data from the database?
Yes, value converters are applied both when saving data to the database and when loading data from the database.