bit*_*001 6 c# entity-framework-core
假设我有一个EF实体类Person,上面有一个PhoneNumber。PhoneNumber以字符串类型存储,但是我希望对Person的所有访问都通过Phone进行,Phone具有一些不错的访问器功能,例如验证或GetAreaCode()。我想将它作为字符串备份在数据库中,但是当查询它时,我想将其作为PhoneNumber返回:
public class Person {
public PhoneNumber Phone { /* Some clever get/set logic here */ }
private string _phoneNumber; // Backing field
}
Run Code Online (Sandbox Code Playgroud)
还是可以让PhoneNumber将自身存储为字符串?如果我只是通过删除上面的后备字段将其包括在模型中,则EF会被构造函数(一个受保护的ctor,具有比一个字符串多的args)和一个副本ctor混淆PhoneNumber(PhoneNumber other)。我可以让EF以某种方式忽略这些吗?
我愿意接受...
我发现可行的唯一方法是使用名称与您的支持字段不匹配的 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;
Run Code Online (Sandbox Code Playgroud)
然后,在DbContext的OnModelCreating方法中,告诉它在数据库表上创建一个充当后备属性的列:
// backing properties
modelBuilder.Entity<Fire>()
.Property<string>("FireType")
.HasField("_fireType")
.UsePropertyAccessMode(PropertyAccessMode.Field);
Run Code Online (Sandbox Code Playgroud)
这样,我终于能够创建一个成功的迁移,使我可以在模型上拥有一个私有字段,在模型上拥有一个公共转换属性,并在数据库表中拥有一个正确命名的列。唯一的问题是,公共财产和私有字段不能共享相同的名称(不共享相同的类型),但是无论如何,这对您而言并非如此。
您可以使用@nbrosz的答案来解决问题,但是如果您使用的是EF Core 2.1,则不再需要执行这种解决方法。您可以使用EF Core 2.1(自2018年5月7日起在候选版本1中)摆脱支持字段,可以使用Microsoft 此处解释的值转换功能:
值转换器允许在读取或写入数据库时转换属性值。此转换可以是从一个值到相同类型的另一个值(例如,加密字符串),也可以是从一种类型的值到另一种类型的值(例如,将枚举值与数据库中的字符串进行来回转换)。
因此,对于您的情况,您只需删除后备字段即可。您不再需要它。您的课程应如下所示:
public class Person
{
public PhoneNumber Phone { /* Some clever get/set logic here */ }
}
Run Code Online (Sandbox Code Playgroud)
在您的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
}
);
Run Code Online (Sandbox Code Playgroud)
而已。实际上它是候选版本,但微软表示:
EF Core 2.1 RC1是一个“上线”版本,这意味着一旦测试您的应用程序可以与RC1一起正常使用,就可以在生产中使用它并获得Microsoft的支持,但是一旦可用,您仍然应该更新到最终的稳定版本。
我剩下的答案用于@nbrosz,因为您正在处理枚举类型。您可以删除背景字段,也可以是EF Core 2.1提供的许多内置值转换器之一。对于枚举到字符串值的转换,我们有类型EnumToStringConverter。对于您在回答中所做的逻辑,您可以将其简化为以下实体:
[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }
Run Code Online (Sandbox Code Playgroud)
我们删除了该NotMapped属性的属性,并且没有逻辑y进行转换。
在您的OnModelCreating方法中,您可以执行以下操作:
var converter = new EnumToStringConverter<FireType>();
modelBuilder
.Entity<Fire>()
.Property(e => e.FireType)
.HasConversion(converter);
Run Code Online (Sandbox Code Playgroud)
您还可以使用以下通用版本,让EF Core为您检测正确的转换器HasConversion<T>:
modelBuilder
.Entity<Fire>()
.Property(e => e.FireType)
.HasConversion<string>();
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢使用流利的配置,则可以使用以下Column数据注释样式,EF Core会为您进行转换:
[Column(TypeName = "nvarchar(20)")]
[Display(Name = "Fire Type")]
public Enums.FireType Type { get; set; }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4650 次 |
| 最近记录: |