[英]EF Core Backing fields - expose property as another type?
假设我有一个 EF 实体类 Person,上面有一个 PhoneNumber。 PhoneNumber 存储为字符串类型,但我希望 Person 上的所有访问都通过 Phone ,它具有一些不错的访问器功能,例如验证或GetAreaCode()
。 我想将它作为字符串返回到数据库中,但是在查询时我想将它作为 PhoneNumber 返回:
public class Person {
public PhoneNumber Phone { /* Some clever get/set logic here */ }
private string _phoneNumber; // Backing field
}
或者我可以让 PhoneNumber 将自己存储为字符串? 如果我只是通过删除上面的支持字段将它包含在模型中,EF 就会被构造函数(一个受保护的构造函数,其参数比一个字符串多一些)和复制构造函数PhoneNumber(PhoneNumber other)
混淆。 我可以让 EF 以某种方式忽略那些吗?
我对想法持开放态度...
您可以使用@nbrosz 的答案来解决您的问题,但如果您使用的是 EF Core 2.1,则不再需要执行此类解决方法。 您可以通过使用 EF Core 2.1(自 2018 年 5 月 7 日起在Release Candidate 1 中)摆脱支持字段,您可以使用 Microsoft 在此处解释的价值转换功能:
值转换器允许在读取或写入数据库时转换属性值。 这种转换可以是从一个值到另一个相同类型的值(例如,加密字符串)或从一种类型的值到另一种类型的值(例如,将枚举值与数据库中的字符串相互转换。)
因此,对于您的情况,您可以删除支持字段。 你不再需要它。 你的类应该是这样的:
public class Person
{
public PhoneNumber Phone { /* Some clever get/set logic here */ }
}
在您的OnModelCreating
方法中,您可以像下面这样配置转换:
modelBuilder.Entity<Person>()
.Property(p => p.Phone)
.HasConversion(
phone => {
// Here you code the logic of how to get the value to store in DB
return ...;
},
dbValue => {
// Here you code the logic of how to construct the PhoneNumber instance from the value to store in DB
}
);
就是这样。 实际上它在候选版本中,但微软说:
EF Core 2.1 RC1 是一个“上线”版本,这意味着一旦您测试您的应用程序与 RC1 一起正常工作,您就可以在生产中使用它并获得 Microsoft 的支持,但是一旦可用,您仍应更新到最终稳定版本.
我的其余答案是针对@nbrosz 的,因为您正在处理枚举类型。 您可以删除支持字段,也可以删除 EF Core 2.1 提供的许多内置值转换器之一。 对于枚举到字符串值的转换,我们有EnumToStringConverter
类型。 对于您在答案中所做的逻辑,您可以将其简化为实体:
[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }
我们删除了属性上的NotMapped
属性,并且没有用于转换的逻辑 y。
在您的OnModelCreating
方法中,您可以这样做:
var converter = new EnumToStringConverter<FireType>();
modelBuilder
.Entity<Fire>()
.Property(e => e.FireType)
.HasConversion(converter);
您还可以使用HasConversion<T>
的通用版本,让 EF Core 为您检测正确的转换器,如下所示:
modelBuilder
.Entity<Fire>()
.Property(e => e.FireType)
.HasConversion<string>();
如果您不喜欢使用流畅的配置,您可以使用如下所示的Column
数据注释属性,EF Core 将为您进行转换:
[Column(TypeName = "nvarchar(20)")]
[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }
我发现在 EF Core 2.0 中有效的唯一方法是创建一个带有 getter/setter 的公共属性,其名称与您的支持字段不匹配,并将其标记为 NotMapped,如下所示:
[NotMapped]
[Display(Name = "Fire Type")]
public Enums.FireType Type
{
get
{
Enums.FireType type;
if (!Enum.TryParse(_fireType, out type))
type = Enums.FireType.Fire; // default
return type;
}
set
{
_fireType = value.ToString();
}
}
private string _fireType;
然后在您的 DbContext 的 OnModelCreating 方法中,告诉它在数据库表上创建一个列,其作用类似于支持属性:
// backing properties
modelBuilder.Entity<Fire>()
.Property<string>("FireType")
.HasField("_fireType")
.UsePropertyAccessMode(PropertyAccessMode.Field);
有了这个,我终于能够创建一个成功的迁移,它允许我在我的模型上有一个私有字段,在模型上有一个公共转换属性,以及我的数据库表中一个正确命名的列。 唯一的问题是公共属性和私有字段不能共享相同的名称(不共享相同的类型),但无论如何都不会是这种情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.