能否将readonly struct用作Entity Framework Core的自有实体?
问题与解决方案
需求
想用Password只读结构体替代User类中的PasswordHash和PasswordSalt两个属性,要求这两个值仍作为用户表的独立列存储,同时保证更新密码时必须同时修改Hash和Salt(为了代码抽象与简洁)。
现有代码
User实体类
public class User { /* 其他属性 */ public Password Password { get; set; } }
Password只读结构体
public readonly struct Password : IEquatable<Password> { public string Hash { get; } public string Salt { get; } public Password(string hash, string salt) { Hash = hash; Salt = salt; } public bool Equals(Password other) { return Hash == other.Hash && Salt == other.Salt; } public override bool Equals(object? obj) { return obj is Password other && Equals(other); } public override int GetHashCode() { return HashCode.Combine(Hash, Salt); } public static bool operator ==(Password left, Password right) => left.Equals(right); public static bool operator !=(Password left, Password right) => !left.Equals(right); }
已知可行但不符合需求的方式
用记录类型可以实现映射,但无法满足“只读属性强制同时更新”的要求:
public record Password(string Hash, string Salt);
正确实现方式(你尝试的OwnsOne配置是有效的)
你用OwnsOne的配置思路完全正确,只需要确认几个前提:
- 使用EF Core 2.0及以上版本(值对象映射从该版本开始支持)
User类的Password属性保留set访问器(当前代码已满足)
最终的OnModelCreating配置如下:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>(entity => { entity.OwnsOne(u => u.Password, navBuilder => { navBuilder.Property(p => p.Hash).HasColumnName("PasswordHash"); navBuilder.Property(p => p.Salt).HasColumnName("PasswordSalt"); }); }); base.OnModelCreating(modelBuilder); }
密码更新方式
因为Password是只读结构体,无法单独修改其Hash或Salt属性,必须创建新实例赋值,刚好满足“同时修改Hash和Salt”的需求:
// 正确的更新方式 user.Password = new Password(newHashedPassword, newSalt);
这样EF Core会自动将Password.Hash映射到数据库的PasswordHash列,Password.Salt映射到PasswordSalt列,完全符合你的需求。
内容的提问来源于stack exchange,提问作者simo026q
相关产品推荐
相关产品推荐

