繁体   English   中英

EF Core 支持字段 - 将属性公开为另一种类型?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM