如何用Linq2DB将POCO类映射到存储儒略日的SQLite表?
问题描述
我有一个包含Reports表的SQLite数据库,表结构如下:
CREATE TABLE IF NOT EXISTS Reports ( Id INTEGER PRIMARY KEY AUTOINCREMENT, ReportName TEXT NOT NULL UNIQUE, CreatedAt REAL NOT NULL )
其中CreatedAt列存储的是儒略日(自公元前4714年11月24日以来的天数),插入数据时需调用julianday函数:
INSERT INTO Reports (ReportName, CreatedAt) VALUES ('Report1', julianday('2023-03-19 13:10:43.254'))
查询时需用strftime函数将其转换为DateTime值:
SELECT ReportName, strftime('%Y-%m-%d %H:%M:%f', CreatedAt) as CreatedAt FROM Reports WHERE Id = 123
我希望创建如下POCO类,并通过Linq2DB与该表完成映射:
public class Report { public long Id { get; set; } public string ReportName { get; set; } public DateTime CreatedAt { get; set; } } public class ReportsContext : DataConnection { public ITable<Report> Reports => this.GetTable<Report>(); }
我了解可通过ExpressionMethodAttribute将属性映射为计算值,但读写数据库时需调用不同的SQL函数,请问能否实现该映射?
解决方案
可以实现,Linq2DB支持通过自定义映射逻辑分别处理**读取(查询)和写入(插入/更新)**时的SQL函数调用,核心是利用ColumnAttribute结合ExpressionMethodAttribute,为读写操作定义不同的转换方法。
步骤1:修改POCO类,添加映射配置
给CreatedAt属性配置读写对应的转换逻辑,同时明确数据库列的类型:
using LinqToDB.Mapping; using System; using System.Linq.Expressions; public class Report { [PrimaryKey, Identity] public long Id { get; set; } [Column(NotNull = true, Unique = true)] public string ReportName { get; set; } // 绑定数据库列,指定类型为REAL [Column(Name = "CreatedAt", DbType = "REAL")] // 读取时:将儒略日转换为DateTime,对应strftime函数 [ExpressionMethod(nameof(MapFromJulianDay))] // 写入时:将DateTime转换为儒略日,对应julianday函数,IsColumnExpression=false表示用于写入 [ExpressionMethod(nameof(MapToJulianDay), IsColumnExpression = false)] public DateTime CreatedAt { get; set; } // 读取转换的表达式方法 public static Expression<Func<Report, DateTime>> MapFromJulianDay() { return r => Sql.Ext.Strftime("%Y-%m-%d %H:%M:%f", r.CreatedAt).ToDateTime(); } // 写入转换的表达式方法 public static Expression<Func<DateTime, object>> MapToJulianDay() { return dt => Sql.Ext.JulianDay(dt).Value; } } public class ReportsContext : DataConnection { public ITable<Report> Reports => this.GetTable<Report>(); }
关键逻辑说明
- 读取逻辑:
MapFromJulianDay方法返回的表达式会让Linq2DB在生成查询SQL时,自动用strftime('%Y-%m-%d %H:%M:%f', CreatedAt)包裹数据库列,完成儒略日到DateTime的转换。 - 写入逻辑:
MapToJulianDay方法的IsColumnExpression = false参数标记这是写入操作的转换规则,Linq2DB生成INSERT/UPDATE语句时,会将DateTime值传入julianday(...)函数,转换为儒略日的REAL值存入数据库。 - DbType配置:指定
DbType = "REAL"确保Linq2DB正确识别数据库列类型,避免类型转换错误。
验证示例
查询操作
执行Linq查询:
using var ctx = new ReportsContext(); var report = ctx.Reports.FirstOrDefault(r => r.Id == 123);
Linq2DB生成的SQL:
SELECT "r"."Id", "r"."ReportName", strftime('%Y-%m-%d %H:%M:%f', "r"."CreatedAt") AS "CreatedAt" FROM "Reports" "r" WHERE "r"."Id" = 123 LIMIT 1
插入操作
执行插入代码:
using var ctx = new ReportsContext(); var newReport = new Report { ReportName = "Report2", CreatedAt = DateTime.Parse("2023-03-20 09:30:15.500") }; ctx.Reports.Insert(newReport);
Linq2DB生成的SQL:
INSERT INTO "Reports" ("ReportName", "CreatedAt") VALUES ('Report2', julianday('2023-03-20 09:30:15.500'))
内容的提问来源于stack exchange,提问作者Ondrej
相关产品推荐
相关产品推荐

