上一篇介绍Entity Framework值转换器以及内置值转换器的相关内容。这一篇将介绍如何自定义值转换器。
对于使用值转换器的属性,可以按正常方式配置这些层面,并将其应用于转换后的数据库类型。 例如,在将枚举转换为字符串时,可以指定数据库列应为非 Unicode,并且最多可存储20个字符。常规的配置方法如下:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Rider>()
.Property(e => e.Mount)
.HasConversion<string>()
.HasMaxLength(20)
.IsUnicode(false);
}
自定义值转换器
上面的示例中,如果按照自定义转换器的写法,是如下格式:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
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)
.HasMaxLength(20)
.IsUnicode(false);
}
如果默认情况下所有 EquineBeast
列都应为 varchar(20)
,则可以将此信息作为的值转换器提供给 ConverterMappingHints 。 例如:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var converter = new ValueConverter<EquineBeast, string>(
v => v.ToString(),
v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v),
new ConverterMappingHints(size: 20, unicode: false));
modelBuilder
.Entity<Rider>()
.Property(e => e.Mount)
.HasConversion(converter);
}
自定义值转换器的更多实例
简单值对象
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; }
}
modelBuilder.Entity<Order>()
.Property(e => e.Price)
.HasConversion(
v => v.Amount,
v => new Dollars(v));
复合值对象
在上面的示例中,值对象类型只包含一个属性。 更常见的情况是,值对象类型组成多个属性,共同构成域概念。 例如,一般 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,
PoundsStirling
}
public class Order
{
public int Id { get; set; }
public Money Price { get; set; }
}
modelBuilder.Entity<Order>()
.Property(e => e.Price)
.HasConversion(
v => JsonSerializer.Serialize(v, null),
v => JsonSerializer.Deserialize<Money>(v, null));
基元集合
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Contents { get; set; }
public ICollection<string> Tags { get; set; }
}
modelBuilder.Entity<Post>()
.Property(e => e.Tags)
.HasConversion(
v => JsonSerializer.Serialize(v, null),
v => JsonSerializer.Deserialize<List<string>>(v, null),
new ValueComparer<ICollection<string>>(
(c1, c2) => c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => (ICollection<string>)c.ToList()));
ICollection<string>
表示可变引用类型。 这意味着, ValueComparer<T> 需要,以便 EF Core 可以正确地跟踪和检测更改。 有关详细信息,请参阅 值 比较器。
阅读全文

公众号近期文章
赞赏支持
0 Responses to “EnityFromework 字段转换 自定义值转换器的使用”