如何在Entity Framework Core中使用类型转换?
如何在Entity Framework Core中使用类型转换?
我猜你是想把客户的订单集合(IEnumerable<Order>)和数据库里的二进制字段(byte[])做转换,要么把集合序列化存进数据库,要么从二进制数据还原出订单列表对吧?下面我给你两种实用的实现方式,你可以根据自己的需求来选。
首先先把你的实体和假设的Order实体整理完整(注意你原来的构造函数写的是User(),应该是笔误改成Customer()啦):
public class Customer { public int Id { get; set; } public string Email { get; set; } public IEnumerable<Order> Orders { get; set; } = []; internal byte[] OrdersArray { get; set; } public Customer() { } } // 假设你的Order实体是这样的,可根据实际情况调整 public class Order { public int OrderId { get; set; } public decimal Amount { get; set; } // 其他订单相关属性... }
方式一:让EF Core直接处理属性转换
这种方式不需要修改实体的结构,直接在映射配置里给Orders属性添加转换规则,让EF自动把集合序列化为二进制数据,存到数据库的OrdersArray列中:
internal class CustomerMap : EntityMappingConfiguration<Customer> { public override void Map(EntityTypeBuilder<Customer> b) { b.ToTable("Customers"); // 忽略内部的OrdersArray属性,我们用Orders属性来映射数据库列 b.Ignore(c => c.OrdersArray); // 配置Orders属性的类型转换逻辑 b.Property(c => c.Orders) .HasColumnName("OrdersArray") // 指定对应数据库的列名 .HasConversion( // 序列化:把订单集合转成byte[] orders => JsonSerializer.SerializeToUtf8Bytes(orders, new JsonSerializerOptions { WriteIndented = false, // 如果有循环引用可以加这个:ReferenceHandler = ReferenceHandler.IgnoreCycles }), // 反序列化:把byte[]还原成订单集合,处理null情况返回空集合 bytes => bytes == null ? Enumerable.Empty<Order>() : JsonSerializer.Deserialize<IEnumerable<Order>>(bytes) ?? Enumerable.Empty<Order>() ) .IsRequired(false); // 允许没有订单的情况,设为非必填 // 其他基础属性配置 b.HasKey(c => c.Id); b.Property(c => c.Email).IsRequired().HasMaxLength(255); } }
方式二:用计算属性封装转换逻辑
如果你更希望让实体自己处理转换逻辑,EF只负责映射二进制字段,可以把Orders改成计算属性,内部通过OrdersArray来读写:
首先修改Customer实体:
public class Customer { public int Id { get; set; } public string Email { get; set; } internal byte[] OrdersArray { get; set; } // 计算属性,不被EF映射,仅用于业务层读写订单 public IEnumerable<Order> Orders { get { if (OrdersArray == null) return Enumerable.Empty<Order>(); return JsonSerializer.Deserialize<IEnumerable<Order>>(OrdersArray) ?? Enumerable.Empty<Order>(); } set { OrdersArray = JsonSerializer.SerializeToUtf8Bytes(value, new JsonSerializerOptions { WriteIndented = false }); } } public Customer() { } }
然后修改映射配置,只映射OrdersArray并忽略Orders计算属性:
internal class CustomerMap : EntityMappingConfiguration<Customer> { public override void Map(EntityTypeBuilder<Customer> b) { b.ToTable("Customers"); // 基础属性配置 b.HasKey(c => c.Id); b.Property(c => c.Email).IsRequired().HasMaxLength(255); // 映射二进制字段 b.Property(c => c.OrdersArray).HasColumnName("OrdersArray").IsRequired(false); // 忽略计算属性Orders,不让EF处理它 b.Ignore(c => c.Orders); } }
注意事项
- 上面用的是.NET自带的
System.Text.Json做序列化,如果你习惯用Newtonsoft.Json,只需要把序列化/反序列化代码换成JsonConvert.SerializeObject和JsonConvert.DeserializeObject就行。 - 要确保
Order实体是可序列化的,比如不要有未处理的循环引用(如果有的话,在序列化选项里配置忽略循环引用)。 - 数据库里的
OrdersArray列要设为VARBINARY(MAX)或者对应的二进制类型,确保能存下序列化后的内容。
备注:内容来源于stack exchange,提问作者Ivan Debono
相关产品推荐
相关产品推荐

