在 SQLite 上使用 Dapper 正确转换 DateTime 属性

Mau*_*tro 5 sqlite datetime dapper

我正在使用 Dapper 向 SQLite 插入对象或从 SQLite 获取对象:一个对象具有 DateTime (和 DateTimeOffset)类型的属性,我必须以毫秒精度保留和检索该属性。我找不到正确检索该值的方法,因为 Dapper 失败并显示:

\n\n
    System.FormatException : String was not recognized as a valid DateTime.\n   in System.DateTimeParse.ParseExactMultiple(String\xc2\xa0s,\xc2\xa0String[]\xc2\xa0formats,\xc2\xa0DateTimeFormatInfo\xc2\xa0dtfi,\xc2\xa0DateTimeStyles\xc2\xa0style)\n   in System.DateTime.ParseExact(String\xc2\xa0s,\xc2\xa0String[]\xc2\xa0formats,\xc2\xa0IFormatProvider\xc2\xa0provider,\xc2\xa0DateTimeStyles\xc2\xa0style)\n   in System.Data.SQLite.SQLiteConvert.ToDateTime(String\xc2\xa0dateText,\xc2\xa0SQLiteDateFormats\xc2\xa0format,\xc2\xa0DateTimeKind\xc2\xa0kind,\xc2\xa0String\xc2\xa0formatString)\n   in System.Data.SQLite.SQLite3.GetDateTime(SQLiteStatement\xc2\xa0stmt,\xc2\xa0Int32\xc2\xa0index)\n   in System.Data.SQLite.SQLite3.GetValue(SQLiteStatement\xc2\xa0stmt,\xc2\xa0SQLiteConnectionFlags\xc2\xa0flags,\xc2\xa0Int32\xc2\xa0index,\xc2\xa0SQLiteType\xc2\xa0typ)\n   in System.Data.SQLite.SQLiteDataReader.GetValue(Int32\xc2\xa0i)\n   in System.Data.SQLite.SQLiteDataReader.GetValues(Object[]\xc2\xa0values)\n   in Dapper.SqlMapper.<>c__DisplayClass5d.<GetDapperRowDeserializer>b__5c(IDataReader\xc2\xa0r) in SqlMapper.cs: line 2587\n   in Dapper.SqlMapper.<QueryImpl>d__11`1.MoveNext() in SqlMapper.cs: line 1572\n   in System.Collections.Generic.List`1..ctor(IEnumerable`1\xc2\xa0collection)\n   in System.Linq.Enumerable.ToList(IEnumerable`1\xc2\xa0source)\n   in Dapper.SqlMapper.Query(IDbConnection\xc2\xa0cnn,\xc2\xa0String\xc2\xa0sql,\xc2\xa0Object\xc2\xa0param,\xc2\xa0IDbTransaction\xc2\xa0transaction,\xc2\xa0Boolean\xc2\xa0buffered,\xc2\xa0Nullable`1\xc2\xa0commandTimeout,\xc2\xa0Nullable`1\xc2\xa0commandType) in SqlMapper.cs: line 1443\n   in Dapper.SqlMapper.Query(IDbConnection\xc2\xa0cnn,\xc2\xa0String\xc2\xa0sql,\xc2\xa0Object\xc2\xa0param,\xc2\xa0IDbTransaction\xc2\xa0transaction,\xc2\xa0Boolean\xc2\xa0buffered,\xc2\xa0Nullable`1\xc2\xa0commandTimeout,\xc2\xa0Nullable`1\xc2\xa0commandType) in SqlMapper.cs: line 1382\n
Run Code Online (Sandbox Code Playgroud)\n\n

我必须尝试什么?列的类型为 DATETIME。

\n\n

我是否必须创建自定义 TypeHandler 并将 DateTime 与格式为“o”的 SQLite 字符串相互转换?

\n\n

短小精悍版本1.38

\n

Ada*_*cki 5

我知道它很旧,但我已经找到了解决方案。经过大量挖掘和分析 Dapper 代码后,我想出了这个(请注意,这是 2019 年):

首先,您必须创建日期时间处理程序:

public class DateTimeHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
    private readonly TimeZoneInfo databaseTimeZone = TimeZoneInfo.Local;
    public static readonly DateTimeHandler Default = new DateTimeHandler();

    public DateTimeHandler()
    {

    }

    public override DateTimeOffset Parse(object value)
    {
        DateTime storedDateTime;
        if (value == null)
            storedDateTime = DateTime.MinValue;
        else
            storedDateTime = (DateTime)value;

        if (storedDateTime.ToUniversalTime() <= DateTimeOffset.MinValue.UtcDateTime)
            return DateTimeOffset.MinValue;
        else
            return new DateTimeOffset(storedDateTime, databaseTimeZone.BaseUtcOffset);
    }

    public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
    {
        DateTime paramVal = value.ToOffset(this.databaseTimeZone.BaseUtcOffset).DateTime;
        parameter.Value = paramVal;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,请注意 Dapper 将 .Net 的类型 DateTimeOffset 转换为 dbType - DateTimeOffset。您需要删除此映射并添加您自己的映射,如下所示:

SqlMapper.RemoveTypeMap(typeof(DateTimeOffset));
SqlMapper.AddTypeHandler(DateTimeHandler.Default);
Run Code Online (Sandbox Code Playgroud)

就这样。现在,每次 Dapper 在模型中看到 DateTimeOffset 属性时,它都会运行 DateTimeHandler 来管理它。


Mau*_*tro 1

我发现无法使用基类型的自定义 TypeHandler,因为在查找 TypeHandler 之前选择了默认 typeMap。

我已经打开了一个问题dapper-dot-net,但同时我已经解决了通过反射将默认 typeMap 替换为新的 typeMap(如前一个减去四个键 DateTime、DateTime?、DateTimeOffset、DateTimeOffset?)的问题。