定义的UserInfo实体,用于保存用户信息,属性PhoneNumber表示用户的手机号码;为了用户信息安全,需要将手机号码进行加密后再保存到数据库,只是为了达到演示的目的,我们采用Base64进行编码。
public class UserInfo { public int Id { get; set; } public string PhoneNumber { get; set; } }Base64ValueConverter表示进行值转换的具体逻辑,继承自泛型ValueConverter<string, string>,具体的逻辑非常简单,不再叙述。
public class Base64ValueConverter : ValueConverter<string, string> { public Base64ValueConverter() : base((v) => ToBase64(v), (v) => FromBase64(v)) { } private static string ToBase64(string input) { if (string.IsNullOrEmpty(input)) return input; var bytes = Encoding.UTF8.GetBytes(input); return Convert.ToBase64String(bytes); } private static string FromBase64(string input) { if (string.IsNullOrEmpty(input)) return input; var bytes = Convert.FromBase64String(input); return Encoding.UTF8.GetString(bytes); } }SampleDbContext表示数据上下文,在OnModelCreating方法中,定义UserInfo实体的PhoneNumber属性需要使用Base64进行值转换。
public class SampleDbContext : DbContext { public DbSet<UserInfo> Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var sqlConnectionStringBuilder = new SqlConnectionStringBuilder { DataSource = "*******", InitialCatalog = "ValueConverterTest", UserID = "sa", Password = "sa" }; optionsBuilder.UseSqlServer(sqlConnectionStringBuilder.ConnectionString); base.OnConfiguring(optionsBuilder); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<UserInfo>().Property(e => e.PhoneNumber).HasConversion(new Base64ValueConverter()); } }下面的代码是对预期的结果进行单测。
[Fact] public async void ValueConverter_Test() { string phoneNumber = "13658556925"; using (SampleDbContext dbContext = new SampleDbContext()) { await dbContext.Database.EnsureDeletedAsync(); await dbContext.Database.EnsureCreatedAsync(); dbContext.Users.Add(new UserInfo() { PhoneNumber = phoneNumber }); await dbContext.SaveChangesAsync(); } UserInfo user; using (SampleDbContext dbContext = new SampleDbContext()) { user = dbContext.Users.Single(); } Assert.NotNull(user); Assert.Equal(phoneNumber, user.PhoneNumber); }运行后,查询数据库中保存的结果:
手机号码 13658556925 在数据库保存的值是 MTM2NTg1NTY5MjU=。
使用值转换的另一个常用场景是将枚举的值存储为字符串类型,默认情况下,枚举的值保存到数据库中是通过整数表示的,如果需要在值存储为字符串类型。
public enum CategoryName { Clothing, Footwear, Accessories } public class Category { public int Id { get; set; } public CategoryName Name { get; set; } }实体Category的Name属性是用枚举表示的,如果在存储时用字符串类型表示,我们可以在DbContext的OnModelCreating方法中使用如下代码,
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Category>().Property(e => e.Name).HasConversion<string>(); }EF Core 默认提供常用类型的转换,我们只需指定存储的类型即可,框架默认支持的类型转换映射表如下:
源类型 目标类型enum int、short、long、sbyte、uint、ushort、ulong、byte、decimal、double、float
bool int、short、long、sbyte、uint、ushort、ulong、byte、decimal、double、float
bool string
bool byte[]
char string
char int、short、long、sbyte、uint、ushort、ulong、byte、decimal、double、float
char byte[]
Guid byte[]
Guid string
byte[] string
string byte[]
DateTime、DateTimeOffset、TimeSpan string、long、byte[]
int、short、long、sbyte、uint、ushort、ulong、byte、decimal、double、float string、byte[]
LINQ GroupBy 解析