电信宽带做网站服务器吗,wordpress给导航添加图片,wordpress调用分类名,中山网站搭建【Entity Framework】你要知道EF中功能序列与值转换 文章目录 【Entity Framework】你要知道EF中功能序列与值转换一、序列1.1 基本用法1.2 配置序列设置 二、值转换2.1 配置值转换器2.2 批量配置值转换器2.3 预定义的转换2.4 ValueConverter类2.5 内置转换器 三、应用3.1 简单…【Entity Framework】你要知道EF中功能序列与值转换 文章目录 【Entity Framework】你要知道EF中功能序列与值转换一、序列1.1 基本用法1.2 配置序列设置 二、值转换2.1 配置值转换器2.2 批量配置值转换器2.3 预定义的转换2.4 ValueConverter类2.5 内置转换器 三、应用3.1 简单值对象3.2 复合值对象3.3 基元的集合3.4 值对象的集合 一、序列
序列在数据库中生成唯一的顺序数值。 序列不与特定表关联可以设置多个表以从同一序列提取值。
1.1 基本用法
可以在模型中设置序列然后使用它为属性生成值
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.HasSequenceint(OrderNumbers);modelBuilder.EntityOrder().Property(o o.OrderNo).HasDefaultValueSql(NEXT VALUE FOR OrderNumbers);
}请注意从序列生成值的特定SQL是特定于数据库的上面的示例适用于 SQL Server 但在其他数据库上将失败。 有关详细信息请查阅数据库的文档。
1.2 配置序列设置
还可以配置序列的其他方面例如其架构、起始值、增量等
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.HasSequenceint(OrderNumbers, schema: shared).StartsAt(1000).IncrementsBy(5);
}二、值转换
值转换器可在从数据库读取或向其中写入属性值时转换属性值。此转换可以是从同一类型的一个值转换为另一个值如加密字符串也可以是从一种类型的值转换为另一种类型的值如数据库中枚举值和字符串的相互转换。
值转换器的指定涉及 ModelClrType 和 ProviderClrType。 模型类型是实体类型中的属性的 .NET 类型。 提供程序类型是数据库提供程序理解的 .NET 类型。 例如若要在数据库中将枚举保存为字符串模型类型是枚举的类型而提供程序类型是 String。 这两种类型可以相同。
使用两个 Func 表达式树定义转换一个从 ModelClrType 转换为 ProviderClrType另一个从 ProviderClrType 转换为 ModelClrType。 使用表达式树的目的是使它们可被编译到数据库访问委托中以便进行高效转换。 表达式树可能包含对复杂转换的转换方法的简单调用。
2.1 配置值转换器
值转换在DbContext.OnModelCreating中配置。如将一个枚举和实体类型定义为
public class Rider
{public int Id { get; set; }public EquineBeast Mount { get; set; }
}public enum EquineBeast
{Donkey,Mule,Horse,Unicorn
}可在OnModelCreating中转换进行如下配置在数据库中将枚举值存储为字符串。可以通过执行从ModelClrType到ProviderClrType的转换另一个执行反向的转换
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.EntityRider().Property(e e.Mount).HasConversion(v v.ToString(),v (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
}绝不会向值转换器传递 null 值。 数据库列中的 null 在实体实例中始终为 null反之亦然。 这使实现转换更容易并允许在可为 null 和不可为 null 的属性之间共享转换。 2.2 批量配置值转换器
为使用相关CLR类型的每个属性配置相同的值转换器很常见。可以使用预约定模型配置为整个模型执行一次此操作而无需手动为每个属性执行此操作。要执行此操作请将值转换器定义为类
public class CurrencyConverter : ValueConverterCurrency, decimal
{public CurrencyConverter(): base(v v.Amount,v new Currency(v)){}
}然后按以下所示在上下文类型中重写ConfigureConventions并配置转换器
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{configurationBuilder.PropertiesCurrency().HaveConversionCurrencyConverter();
}2.3 预定义的转换
EF Core含有许多预定义转换不需要手动编写转换函数。而是根据模型中的属性类型和请求的数据库提供程序类型选取要使用的转换。
如下面的示例中使用了从枚举到字符串的转换但当提供程序类型配置为string时EF Core实际上会使用HasConversion的泛型类型自动执行此转换
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.EntityRider().Property(e e.Mount).HasConversionstring();
}可通过显式地指定数据库列类型实现相同的操作。 例如如果实体类型的定义如下
数据注释
public class Rider2
{public int Id { get; set; }[Column(TypeName nvarchar(24))]public EquineBeast Mount { get; set; }
}Flument API
modelBuilder.EntityRider2().Property(e e.Mount).HasColumnType(nvarchar(24));然后枚举值会被保存为数据库中的字符串
2.4 ValueConverter类
上面示例调用HasConversion会创建一个ValueConverterTModel,TProvider实例并在属性上设置它。可改为显示地创建ValueConverter。示例如
protected override void OnModelCreating(ModelBuilder modelBuilder)
{var converter new ValueConverterEquineBeast, string(v v.ToString(),v (EquineBeast)Enum.Parse(typeof(EquineBeast), v));modelBuilder.EntityRider().Property(e e.Mount).HasConversion(converter);
}多个属性使用同一个转换时这非常有用。
2.5 内置转换器
如上所述EF Core附带了一组预定义ValueConverterTModel,TProvider类这些类位于Microsoft.EntityFrameworkCore.Storage.ValueConversion命名空间中。 在许多情况下EF 将根据模型中属性的类型和在数据库中请求的类型选择适当的内置转换器正如上面的枚举转换示例所示。 例如对 bool 属性使用 .HasConversionint() 会使 EF Core 将布尔值转换为数值零和一
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.EntityUser().Property(e e.IsActive).HasConversionint();
}这种做法与创建一个内置BoolToZeroOneConverterTProvider的实例并进行显式设置在功能上的效果一样
protected override void OnModelCreating(ModelBuilder modelBuilder)
{var converter new BoolToZeroOneConverterint();modelBuilder.EntityUser().Property(e e.IsActive).HasConversion(converter);
}三、应用
3.1 简单值对象
此示例使用简单类型来包装基元类型。 希望模型中的类型比基元类型更具体因而更具类型安全性时这很有用。 在此示例中该类型为 Dollars它包装小数基元
public readonly struct Dollars
{public Dollars(decimal amount) Amount amount; public decimal Amount { get; }public override string ToString() $${Amount};
}这可用于实体类型中
public class Order
{public int Id { get; set; }public Dollars Price { get; set; }
}还可在存储到数据库中时被转换为基本 decimal
modelBuilder.EntityOrder().Property(e e.Price).HasConversion(v v.Amount,v new Dollars(v));3.2 复合值对象
在上一个示例中值对象类型仅包含一个属性。更常见的是值对象类型组成共同构成一个域概念的多个属性。如一个通用的Money类型包含金额和货币。
public readonly struct Money
{[JsonConstructor]public Money(decimal amount, Currency currency){Amount amount;Currency currency;}public override string ToString() (Currency Currency.UsDollars ? $ : £) Amount;public decimal Amount { get; }public Currency Currency { get; }
}
public enum Currency
{UsDollars,PoundsSterling
}可以像以前一样在实体类型中使用此值对象
public class Order
{public int Id { get; set; }public Money Price { get; set; }
}值转换器目前只能执行值与一个数据库列之间的转换。此限制意味着对象的所有属性值都必须被编码为一个列值。对此通常的处理方法是在对象进入数据库中时序列化该对象再在它退出数据库时反序列化。如,使用System.Text.Json:
modelBuilder.EntityOrder().Property(e e.Price).HasConversion(v JsonSerializer.Serialize(v, (JsonSerializerOptions)null),v JsonSerializer.DeserializeMoney(v, (JsonSerializerOptions)null));3.3 基元的集合
序列化还可用于存储基元值的集合。 如
public class Post
{public int Id { get; set; }public string Title { get; set; }public string Contents { get; set; }public ICollectionstring Tags { get; set; }
}再次使用System.Text.Json:
modelBuilder.EntityPost().Property(e e.Tags).HasConversion(v JsonSerializer.Serialize(v, (JsonSerializerOptions)null),v JsonSerializer.DeserializeListstring(v, (JsonSerializerOptions)null),new ValueComparerICollectionstring((c1, c2) c1.SequenceEqual(c2),c c.Aggregate(0, (a, v) HashCode.Combine(a, v.GetHashCode())),c (ICollectionstring)c.ToList()));ICollectionstring 表示可变引用类型。 也就是说需要使用 ValueComparer这样 EF Core 才能正确地跟踪和监测更改。
3.4 值对象的集合
结合前两个示例我们可以创建一个值对象集合。 例如假设有一个 AnnualFinance 类型它为博客一年的财务状况建模
public readonly struct AnnualFinance
{[JsonConstructor]public AnnualFinance(int year, Money income, Money expenses){Year year;Income income;Expenses expenses;}public int Year { get; }public Money Income { get; }public Money Expenses { get; }public Money Revenue new Money(Income.Amount - Expenses.Amount, Income.Currency);
}此类型构成几个我们先前创建的 Money 类型
public readonly struct Money
{[JsonConstructor]public Money(decimal amount, Currency currency){Amount amount;Currency currency;}public override string ToString() (Currency Currency.UsDollars ? $ : £) Amount;public decimal Amount { get; }public Currency Currency { get; }
}
public enum Currency
{UsDollars,PoundsSterling
}然后我们可以向实体类型添加一个 AnnualFinance 集合
public class Blog
{public int Id { get; set; }public string Name { get; set; }public IListAnnualFinance Finances { get; set; }
}接下来再次使用序列化来进行存储
modelBuilder.EntityBlog().Property(e e.Finances).HasConversion(v JsonSerializer.Serialize(v, (JsonSerializerOptions)null),v JsonSerializer.DeserializeListAnnualFinance(v, (JsonSerializerOptions)null),new ValueComparerIListAnnualFinance((c1, c2) c1.SequenceEqual(c2),c c.Aggregate(0, (a, v) HashCode.Combine(a, v.GetHashCode())),c (IListAnnualFinance)c.ToList()));