1. 程式人生 > 實用技巧 >Entity Framework Core The same thing can be achieved by explicitly specifying the column type. For example, if the entity type is defined like so:- 建立並配置模型-值轉換器 Value Conversions

Entity Framework Core The same thing can be achieved by explicitly specifying the column type. For example, if the entity type is defined like so:- 建立並配置模型-值轉換器 Value Conversions

值轉換

  值轉換器允許在從資料庫讀取或寫入資料庫時轉換屬性值。這種轉換可以從一個值轉換到另一個相同型別的值(例如,加密字串),也可以從一種型別的值轉換到另一種型別的值(例如,將列舉值轉換為資料庫中的字串,或者將列舉值轉換為資料庫中的字串)。

1、基礎知識

  值轉換器是根據ModelClrType(模型型別)和ProviderClrType(提供程式型別)指定的。模型型別是實體型別中屬性的. net型別。提供程式型別是資料庫提供程式所能理解的.net型別。例如,要將列舉儲存為資料庫中的字串,模型型別是列舉的型別,提供者型別是String。這兩種型別可以是相同的。

  轉換是使用兩個Func表示式樹定義的:一個從ModelClrType到ProviderClrType,另一個從ProviderClrType到ModelClrType。表示式樹可以被編譯到資料庫訪問程式碼中,以實現有效的轉換。對於複雜的轉換,表示式樹可以是對執行轉換的方法的簡單呼叫。

2、配置一個值轉換器

  值轉換是在DbContext的OnModelCreating屬性上定義的。例如,考慮定義如下的列舉和實體型別:

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

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

  然後可以在OnModelCreate中定義轉換(Conversion),將列舉值儲存為字串(例如,“Donkey”,“Mule”,…)在資料庫中:

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

  空值永遠不會傳遞給值轉換器。這使得轉換的實現更容易,並允許它們在可為空和不可為空的屬性之間共享。

3、值轉換類 ValueConverter class

  如上所示呼叫HasConversion將建立一個ValueConverter例項,並在屬性上設定它。相反,可以顯式地建立ValueConverter。例如:

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);

  當多個屬性使用相同的轉換時,這很有用。目前還沒有辦法在一個地方指定給定型別的每個屬性必須使用相同的值轉換器。

4、內建轉換器

  EF Core 附帶一組預定義的ValueConverter類,這些類位於Microsoft.EntityFrameworkCore.Storage.ValueConversion名稱空間中。這些是:

  • BoolToZeroOneConverter-布林值到一個0
  • BoolToStringConverter-Bool 到字串(如 "Y" 和 "N")
  • BoolToTwoValuesConverter-布林值到任意兩個值
  • BytesToStringConverter-位元組陣列到 Base64 編碼的字串
  • CastingConverter-只需要型別強制轉換的轉換
  • CharToStringConverter-Char 到單字元字串
  • DateTimeOffsetToBinaryConverter-DateTimeOffset 到二進位制編碼的64位值
  • DateTimeOffsetToBytesConverter-DateTimeOffset 到位元組陣列
  • DateTimeOffsetToStringConverter-DateTimeOffset 到字串
  • DateTimeToBinaryConverter-DateTime 到64位值,包括 Datetimekind.utc
  • DateTimeToStringConverter-DateTime 到 string
  • DateTimeToTicksConverter-DateTime 到計時週期
  • EnumToNumberConverter-列舉到基礎數字
  • EnumToStringConverter-列舉到字串
  • GuidToBytesConverter-Guid 到位元組陣列
  • GuidToStringConverter-Guid 到字串
  • NumberToBytesConverter-任何數值到位元組陣列
  • NumberToStringConverter-任何數值到字串
  • StringToBytesConverter-字串到 UTF8 位元組
  • TimeSpanToStringConverter-TimeSpan 到字串
  • TimeSpanToTicksConverter-TimeSpan 到計時週期

  請注意,EnumToStringConverter包含在這個列表中。這意味著不需要顯式地指定轉換,如上所示。相反,只需使用內建轉換器:

var converter = new EnumToStringConverter<EquineBeast>();

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

  請注意,所有內建轉換器都是無狀態的,因此多個屬性可以安全地共享單個例項。

5、預定義的轉換

  對於內建轉換器存在的常見轉換,不需要顯式指定轉換器。相反,只要配置應該使用哪種提供者型別,EF就會自動使用適當的內建轉換器。上面的例子使用列舉到字串的轉換,但是如果提供者型別被配置,EF實際上會自動這樣做:

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

  通過顯式地指定列型別,也可以實現同樣的目的。例如,實體型別是這樣定義的:

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

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

  然後enum值將作為字串儲存在資料庫中,無需在onmodelcreate中進行任何進一步的配置。

6、限制

  值轉換系統存在一些已知的當前限制:

  • 如上所述,null無法轉換。
  • 目前沒有辦法將一個屬性轉換為多個列,反之亦然。
  • 使用值轉換可能會影響 EF Core 將表示式轉換為 SQL 的能力。這種情況下會記錄警告。將來的版本將考慮刪除這些限制。