首页 > 解决方案 > 尝试使用 .Net Core 中的值转换器将模型中的 long 转换为具有多个字段的对象

问题描述

我正在制作一个连接到硬件的 .net 核心应用程序,该应用程序负责更新设置并将它们保存到数据库中。硬件和数据库中的所有时间值都以秒为单位存储为 long,但客户端希望时间可以在两个单独的字段(分钟和秒)中进行编辑,然后作为单个 long 值保存回数据库和机器。

我试图编写一个值转换器来将 long 转换为 MinutesAndSecondsTime 对象。但是,我不确定如何指定 MinutesAndSecondsTime 对象(或者是否可以完成),因为它会生成外键 id 并且无法引用。

模型(删除了附加字段)是:

public class Machine: BaseEntity
{
    public long Delay { get; set; }
    public MinutesAndSecondsTime SplitDelay { get; set; }
    public long Runtime { get; set; }
    public MinutesAndSecondsTime SplitRuntime { get; set; }
}

我试图将这些值转换为的对象如下:

public class MinutesAndSecondsTime
{
    public MinutesAndSecondsTime(long time)
    {
        Minutes = time / 60;
        Seconds = time % 60;
    }

    public long Minutes { get; set; }
    public long Seconds { get; set; }
}

然后我有一个 TimeConverter 类,它应该处理转换:

public class TimeConverter : ValueConverter<long, MinuteSecondTime>
{
    public TimeConverter(ConverterMappingHints mappingHints = null) : 
        base(convertToProviderExpression, convertFromProviderExpression, 
        mappingHints)
    { }

    private static Expression<Func<long, MinuteSecondTime>> convertToProviderExpression = x => ToTimeObject(x);
    private static Expression<Func<MinuteSecondTime, long>> convertFromProviderExpression = x => ToTimeLong(x);

    private static MinuteSecondTime ToTimeObject(long time)
    {
        return new MinuteSecondTime(time);
    }

    private static long ToTimeLong(MinuteSecondTime time)
    {
        return time.Minutes * 60 + time.Seconds;
    }
}

在 ApplicationDbContext 中,这应用于 OnModelCreating 函数:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    var entity = modelBuilder.Model.GetEntityTypes()
        .Where(x => x.Name == "TestApp.Machine").First();
    var delayProperty = entity.GetProperties().Where(y => y.Name == "Delay").First();
    var runtimeProperty = entity.GetProperties().Where(y => y.Name == "Runtime").First();

    delayProperty.SetValueConverter(new TimeConverter());
    runtimeProperty.SetValueConverter(new TimeConverter());
}

我目前得到:

System.ArgumentException:“模型类型“MinuteSecondTime”的转换器不能用于“Article.Delay”,因为它的类型是“long”。

尝试将转换器添加到 OnModelCreating 中的字段时。据我所知,价值转换似乎只接受一个字段。有没有办法解决这个问题或替代解决方案?

标签: c#asp.net-coremodel-view-controller

解决方案


据我了解,您正在尝试做的是在数据库中有一个长数据类型,但它被转换为MinutesAndSecondsTime.

我会将您的机器模型更改为如下所示:

public class Machine
{
  [Key]
  public int Id { get; set; }

  [Column(TypeName = "integer")]
  public MinutesAndSecondsTime Delay { get; set; }

  [Column(TypeName = "integer")]
  public MinutesAndSecondsTime Runtime { get; set; }
}

您可以将类型更改为intbigint取决于您正在使用的数据库提供程序。我使用 SQLite。

ValueConverter应该像这样实现:

public class TimeConverter : ValueConverter<MinutesAndSecondsTime, long>
{
    public TimeConverter(ConverterMappingHints mappingHints = null) :
        base(convertToProviderExpression, convertFromProviderExpression,
        mappingHints)
    { }

    private static Expression<Func<MinutesAndSecondsTime, long>> convertToProviderExpression = x => ToTimeLong(x);

    private static Expression<Func<long, MinutesAndSecondsTime>> convertFromProviderExpression = x => ToTimeObject(x);

    private static MinutesAndSecondsTime ToTimeObject(long time)
    {
        return new MinutesAndSecondsTime(time);
    }

    private static long ToTimeLong(MinutesAndSecondsTime time)
    {
        return time.Minutes * 60 + time.Seconds;
    }
}

请注意,我将类型参数切换为TimeConverter. 您可以在此处了解有关 ValueConverter的更多信息

然后你可以OnModelCreating像这样实现:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
       modelBuilder
            .Entity<Machine>()
            .Property(e => e.Delay)
            .HasConversion(new TimeConverter());

        modelBuilder
           .Entity<Machine>()
           .Property(e => e.Runtime)
           .HasConversion(new TimeConverter());
}

MinutesAndSecondsTime然后当使用对象将值插入数据库时​​,如下所示:

db.Machines.Add(new Machine()
{
  Delay = new MinutesAndSecondsTime(10000)
});
db.SaveChanges();

推荐阅读