轉自https://www.cnblogs.com/hiwuchong/p/14160299.html
轉換
值轉換器允許在從資料庫讀取或寫入資料庫時轉換屬性值。這種轉換可以從一個值轉換到另一個相同類型的值(例如,加密字元串),也可以從一種類型的值轉換到另一種類型的值(例如,将枚舉值轉換為資料庫中的字元串,或者将枚舉值轉換為資料庫中的字元串)。
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
命名空間中。 這些是:
-
-布爾值到一個0BoolToZeroOneConverter
-
-Bool 到字元串(如 "Y" 和 "N")BoolToStringConverter
-
-布爾值到任意兩個值BoolToTwoValuesConverter
-
-位元組數組到 Base64 編碼的字元串BytesToStringConverter
-
-隻需要類型強制轉換的轉換CastingConverter
-
-Char 到單字元字元串CharToStringConverter
-
-DateTimeOffset 到二進制編碼的64位值DateTimeOffsetToBinaryConverter
-
-DateTimeOffset 到位元組數組DateTimeOffsetToBytesConverter
-
-DateTimeOffset 到字元串DateTimeOffsetToStringConverter
-
-DateTime 到64位值,包括 Datetimekind.utcDateTimeToBinaryConverter
-
-DateTime 到 stringDateTimeToStringConverter
-
-DateTime 到計時周期DateTimeToTicksConverter
-
-枚舉到基礎數字EnumToNumberConverter
-
-枚舉到字元串EnumToStringConverter
-
-Guid 到位元組數組GuidToBytesConverter
-
-Guid 到字元串GuidToStringConverter
-
-任何數值到位元組數組NumberToBytesConverter
-
-任何數值到字元串NumberToStringConverter
-
-字元串到 UTF8 位元組StringToBytesConverter
-
-TimeSpan 到字元串TimeSpanToStringConverter
-
-TimeSpan 到計時周期TimeSpanToTicksConverter
請注意,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 的能力。 這種情況下會記錄警告。 将來的版本将考慮删除這些限制。