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

在linq2db v5.3.2查询中使用自定义方法的问题求助

问题描述

使用linq2db 5.3.2版本(因关联其他应用无法升级,版本兼容问题会引发故障),需要在查询中实现去除字符串非数字字符的逻辑(例如将"A54778"转换为54778),用于表关联。

尝试过两种方案均失败:

  • 自定义ExtractNumber方法,linq2db无法解析该方法导致报错
  • 使用Regex.Replace(d.InvoiceNumber.ToString(), "[^0-9]", ""),同样无法被linq2db转换为SQL

若先将所有数据加载到内存中,自定义方法可正常运行,但数据量极大,这种方式性能极差。

需求:修复查询,最好无需创建数据库端函数。

原代码如下:

public void InsertPayoffData()
{
    using var db = _db();

    var query =
        from p in db.Payoff1C
        join d in db.Debit on new { Number = p.InvoiceNumber, Date = p.InvoiceDate }
            equals new { Number = ExtractNumber(d.InvoiceNumber.ToString()), Date = d.InvoiceDate }
        join k in db.Kredit on new { Number = p.PayDocNumber.ToString(), Date = p.PayDocDate }
            equals new { Number = ExtractNumber(k.PayDocNumber.ToString()), Date = k.PayDocDate }
        where !db.Payoff.Any(pf =>
            pf.Debit_ID == d.DebitId &&
            pf.Kredit_ID == k.Kredit_ID)
        select new Payoff
        {
            Debit_ID = d.DebitId,
            Kredit_ID = k.Kredit_ID,
            PayoffDate = p.PayDocDate,
            PayoffSum = p.PayOffSum,
            PayoffType = 0
        };

    var result = query.ToList();
    db.BulkInsert(result);
}

private int ExtractNumber(string value)
{
    if (string.IsNullOrEmpty(value))
    {
        return 0;
    }

    var numberString = new string(value.Where(char.IsDigit).ToArray());
    return int.TryParse(numberString, out int result) ? result : 0;
}
解决方案

针对你的情况,有两种无需创建数据库端函数的方案,适配linq2db 5.3.2版本:

方案一:使用linq2db内置函数实现数字提取

利用linq2db提供的Sql.CharIsDigit(判断字符是否为数字)和Sql.TryConvert(安全类型转换)函数,将自定义逻辑转换为linq2db可解析的表达式,从而在数据库端执行过滤和转换,无需加载全量数据到内存。

修改后的代码如下:

public void InsertPayoffData()
{
    using var db = _db();

    var query =
        from p in db.Payoff1C
        join d in db.Debit on new { Number = p.InvoiceNumber, Date = p.InvoiceDate }
            equals new 
            { 
                Number = Sql.TryConvert<int>(
                    new string(d.InvoiceNumber.Where(c => Sql.CharIsDigit(c)).ToArray()), 
                    0
                ), 
                Date = d.InvoiceDate 
            }
        join k in db.Kredit on new { Number = p.PayDocNumber.ToString(), Date = p.PayDocDate }
            equals new 
            { 
                Number = Sql.TryConvert<int>(
                    new string(k.PayDocNumber.Where(c => Sql.CharIsDigit(c)).ToArray()), 
                    0
                ), 
                Date = k.PayDocDate 
            }
        where !db.Payoff.Any(pf =>
            pf.Debit_ID == d.DebitId &&
            pf.Kredit_ID == k.Kredit_ID)
        select new Payoff
        {
            Debit_ID = d.DebitId,
            Kredit_ID = k.Kredit_ID,
            PayoffDate = p.PayDocDate,
            PayoffSum = p.PayOffSum,
            PayoffType = 0
        };

    var result = query.ToList();
    db.BulkInsert(result);
}

说明:

  • Sql.CharIsDigit会被linq2db转换为对应数据库的字符判断逻辑(如SQL Server的LIKE '[0-9]',MySQL的REGEXP '^[0-9]$')
  • Sql.TryConvert<int>(..., 0)确保当过滤后的字符串无法转换为整数时,返回默认值0,避免转换错误

方案二:调用数据库原生正则替换函数(依赖数据库支持)

如果你的数据库版本支持正则表达式替换(例如SQL Server 2017+的REGEXP_REPLACE、PostgreSQL的regexp_replace),可以直接通过linq2db的Sql.Functions.RegExpReplace调用数据库原生函数,简化数字提取逻辑:

以SQL Server为例,修改关联条件中的Number部分:

Number = Sql.TryConvert<int>(Sql.Functions.RegExpReplace(d.InvoiceNumber.ToString(), "[^0-9]", ""), 0)

注意:需要确认你的数据库版本支持该正则替换函数,且linq2db 5.3.2对应该数据库的提供商已实现该函数的映射。


内容的提问来源于stack exchange,提问作者user19627737

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 23:17:03