TimeOnly support instead of TimeSpan

I have a Time column in SQL Server. Historically this would be mapped to a TimeSpan in C# world. However I want to utilize the TimeOnly property.

I have a definition that looks as follows:
image

Then in code:
image

However when saving this object I get the following exception:
image

When trying to read out the value, it is always “00:00:00”.

I am assuming I will need to implement some kind of converter to support this, but am not sure where to start or what exactly to convert between.

Can you please provide some assistance?

Does this make sense as a converter?

    public class SqlServerTimeOnlyConverter : SqlServerTimeConverter
    {
        public override DbType DbType => DbType.Time;

        public override object ToDbValue(Type fieldType, object value)
        {
            if (value is TimeOnly timeOnly)
            {
                return timeOnly.ToString("o");
            }
            else if (value is string str && TimeOnly.TryParseExact(str, "HH:mm:ss", out var time))
            {
                return time.ToString("o");
            }

            return base.FromDbValue(fieldType, value);
        }

        public override object FromDbValue(Type fieldType, object value)
        {
            object x = base.FromDbValue(fieldType, value);
            if(x is TimeSpan ts)
            {
                return new TimeOnly(ts.Ticks);
            }

            return x;
        }
    }

I wouldn’t override SqlServerTimeConverter.cs which uses the DateTime ADO .NET DbType for its TIME column. I’d copy ColumnDefinition and inherit OrmLiteConverter directly.

    public class SqlServerTimeOnlyConverter : OrmLiteConverter
    {
        public override DbType DbType => DbType.Time;

        public int? Precision { get; set; }
        public override string ColumnDefinition => Precision != null
               ? $"TIME({Precision.Value})"
               : "TIME";

        public override object ToDbValue(Type fieldType, object value)
        {
            if (value is TimeOnly timeOnly)
            {
                return timeOnly.ToString("o");
            }
            else if (value is string str && TimeOnly.TryParseExact(str, "HH:mm:ss", out var time))
            {
                return time.ToString("o");
            }

            return base.FromDbValue(fieldType, value);
        }

        public override object FromDbValue(Type fieldType, object value)
        {
            if (value is TimeSpan ts)
            {
                return new TimeOnly(ts.Ticks);
            }

            return base.FromDbValue(fieldType, value);
        }
    }

To be complete you’ll also want to override ToQuotedString() to return the format that SQL Server natively understands for comparison of a TIME column type in a non parameterized query, e.g. Where Column = '1:02:03'