You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:22:55