值转换Value Conversions

备注

此功能是 EF Core 2.1 中的新增功能。This feature is new in EF Core 2.1.

值转换器允许在读取或写入数据库时转换属性值。Value converters allow property values to be converted when reading from or writing to the database. 此转换可以从一个值转换为同一类型的另一个值 (例如,将字符串) 或从一种类型的值加密为另一种类型的值 (例如,在数据库中将枚举值与字符串相互转换。 ) This conversion can be from one value to another of the same type (for example, encrypting strings) or from a value of one type to a value of another type (for example, converting enum values to and from strings in the database.)

基础知识Fundamentals

值转换器以和的形式指定 ModelClrType ProviderClrTypeValue converters are specified in terms of a ModelClrType and a ProviderClrType. 模型类型是实体类型中的属性的 .NET 类型。The model type is the .NET type of the property in the entity type. 提供程序类型是数据库提供程序理解的 .NET 类型。The provider type is the .NET type understood by the database provider. 例如,若要将枚举作为字符串保存在数据库中,模型类型是枚举的类型,而提供程序类型为 StringFor example, to save enums as strings in the database, the model type is the type of the enum, and the provider type is String. 这两种类型可以相同。These two types can be the same.

使用两个 Func 表达式树来定义转换:一个从 ModelClrTypeProviderClrType ,另一个由 ProviderClrTypeModelClrTypeConversions are defined using two Func expression trees: one from ModelClrType to ProviderClrType and the other from ProviderClrType to ModelClrType. 使用表达式树,以便可以将它们编译到数据库访问代码中以便进行有效的转换。Expression trees are used so that they can be compiled into the database access code for efficient conversions. 对于复杂转换,表达式树可能是对执行转换的方法的简单调用。For complex conversions, the expression tree may be a simple call to a method that performs the conversion.

配置值转换器Configuring a value converter

值转换是在的中的属性上定义的 OnModelCreating DbContextValue conversions are defined on properties in the OnModelCreating of your DbContext. 例如,假设枚举和实体类型定义为:For example, consider an enum and entity type defined as:

public class Rider
{
    public int Id { get; set; }
    public EquineBeast Mount { get; set; }
}

public enum EquineBeast
{
    Donkey,
    Mule,
    Horse,
    Unicorn
}

然后,可以在中定义转换, OnModelCreating 以将枚举值存储为字符串 (例如,在数据库中指定 "Donkey"、"Mule" 和 ... ) :Then conversions can be defined in OnModelCreating to store the enum values as strings (for example, "Donkey", "Mule", ...) in the database:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Rider>()
        .Property(e => e.Mount)
        .HasConversion(
            v => v.ToString(),
            v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
}

备注

null值绝不会传递到值转换器。A null value will never be passed to a value converter. 这使得转换的实现变得更简单,并使其能够在可以为 null 和不可为 null 的属性之间共享。This makes the implementation of conversions easier and allows them to be shared amongst nullable and non-nullable properties.

ValueConverter 类The ValueConverter class

HasConversion如上所述调用会创建一个 ValueConverter 实例,并在属性中设置该实例。Calling HasConversion as shown above will create a ValueConverter instance and set it on the property. ValueConverter可以显式创建。The ValueConverter can instead be created explicitly. 例如:For example:

var converter = new ValueConverter<EquineBeast, string>(
    v => v.ToString(),
    v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));

modelBuilder
    .Entity<Rider>()
    .Property(e => e.Mount)
    .HasConversion(converter);

当多个属性使用相同的转换时,这可能很有用。This can be useful when multiple properties use the same conversion.

备注

当前无法在一个位置指定给定类型的每个属性都必须使用相同的值转换器。There is currently no way to specify in one place that every property of a given type must use the same value converter. 将来的版本将考虑此功能。This feature will be considered for a future release.

内置转换器Built-in converters

EF Core 附带一组预定义的 ValueConverter 类,这些类位于 Microsoft.EntityFrameworkCore.Storage.ValueConversion 命名空间中。EF Core ships with a set of pre-defined ValueConverter classes, found in the Microsoft.EntityFrameworkCore.Storage.ValueConversion namespace. 它们是:These are:

  • BoolToZeroOneConverter -布尔值为零和一个BoolToZeroOneConverter - Bool to zero and one
  • BoolToStringConverter -Bool 到字符串(如 "Y" 和 "N")BoolToStringConverter - Bool to strings such as "Y" and "N"
  • BoolToTwoValuesConverter -布尔值到任意两个值BoolToTwoValuesConverter - Bool to any two values
  • BytesToStringConverter -字节数组到 Base64 编码的字符串BytesToStringConverter - Byte array to Base64-encoded string
  • CastingConverter -只需要类型强制转换的转换CastingConverter - Conversions that require only a type cast
  • CharToStringConverter -Char 到单字符字符串CharToStringConverter - Char to single character string
  • DateTimeOffsetToBinaryConverter -DateTimeOffset 到二进制编码的64位值DateTimeOffsetToBinaryConverter - DateTimeOffset to binary-encoded 64-bit value
  • DateTimeOffsetToBytesConverter -DateTimeOffset 到字节数组DateTimeOffsetToBytesConverter - DateTimeOffset to byte array
  • DateTimeOffsetToStringConverter -DateTimeOffset 到字符串DateTimeOffsetToStringConverter - DateTimeOffset to string
  • DateTimeToBinaryConverter -DateTime 到64位值,包括 Datetimekind.utcDateTimeToBinaryConverter - DateTime to 64-bit value including DateTimeKind
  • DateTimeToStringConverter -DateTime 到 stringDateTimeToStringConverter - DateTime to string
  • DateTimeToTicksConverter -DateTime 到计时周期DateTimeToTicksConverter - DateTime to ticks
  • EnumToNumberConverter -枚举到基础数字EnumToNumberConverter - Enum to underlying number
  • EnumToStringConverter -枚举到字符串EnumToStringConverter - Enum to string
  • GuidToBytesConverter -Guid 到字节数组GuidToBytesConverter - Guid to byte array
  • GuidToStringConverter -Guid 到字符串GuidToStringConverter - Guid to string
  • NumberToBytesConverter -任何数值到字节数组NumberToBytesConverter - Any numerical value to byte array
  • NumberToStringConverter -任何数值到字符串NumberToStringConverter - Any numerical value to string
  • StringToBytesConverter -字符串到 UTF8 字节StringToBytesConverter - String to UTF8 bytes
  • TimeSpanToStringConverter -TimeSpan 到字符串TimeSpanToStringConverter - TimeSpan to string
  • TimeSpanToTicksConverter -TimeSpan 到计时周期TimeSpanToTicksConverter - TimeSpan to ticks

请注意, EnumToStringConverter 此列表中包含。Notice that EnumToStringConverter is included in this list. 这意味着无需显式指定转换,如上所示。This means that there is no need to specify the conversion explicitly, as shown above. 相反,只需使用内置转换器:Instead, just use the built-in converter:

var converter = new EnumToStringConverter<EquineBeast>();

modelBuilder
    .Entity<Rider>()
    .Property(e => e.Mount)
    .HasConversion(converter);

请注意,所有内置的转换器都是无状态的,因此,多个属性可以安全地共享单个实例。Note that all the built-in converters are stateless and so a single instance can be safely shared by multiple properties.

预定义的转换Pre-defined conversions

对于内置转换器存在的常见转换,无需显式指定转换器。For common conversions for which a built-in converter exists there is no need to specify the converter explicitly. 相反,只需配置应使用的提供程序类型,EF 会自动使用适当的内置转换器。Instead, just configure which provider type should be used and EF will automatically use the appropriate built-in converter. 枚举到字符串的转换用作上面的示例,但如果配置了提供程序类型,则 EF 实际上会自动执行此操作:Enum to string conversions are used as an example above, but EF will actually do this automatically if the provider type is configured:

modelBuilder
    .Entity<Rider>()
    .Property(e => e.Mount)
    .HasConversion<string>();

可以通过显式指定列类型来实现相同的目的。The same thing can be achieved by explicitly specifying the column type. 例如,如果定义了实体类型,如下所示:For example, if the entity type is defined like so:

public class Rider
{
    public int Id { get; set; }

    [Column(TypeName = "nvarchar(24)")]
    public EquineBeast Mount { get; set; }
}

然后,枚举值将作为字符串保存在数据库中,而不会在中进行任何进一步的配置 OnModelCreatingThen the enum values will be saved as strings in the database without any further configuration in OnModelCreating.

限制Limitations

值转换系统存在一些已知的当前限制:There are a few known current limitations of the value conversion system:

  • 如上所述, null 无法转换。As noted above, null cannot be converted.
  • 目前没有办法将一个属性转换为多个列,反之亦然。There is currently no way to spread a conversion of one property to multiple columns or vice-versa.
  • 使用值转换可能会影响 EF Core 将表达式转换为 SQL 的能力。Use of value conversions may impact the ability of EF Core to translate expressions to SQL. 这种情况下会记录警告。A warning will be logged for such cases. 将来的版本将考虑删除这些限制。Removal of these limitations is being considered for a future release.