介尘部落

文学|音乐|休闲娱乐|计算机技术|地球科学|社会学——知识成就命运


EnityFromework 字段转换 自定义值转换器的使用

上一篇介绍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 字段转换 自定义值转换器的使用”

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

×