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

Xamarin项目SQLite.NET Filter谓词使用自定义方法报错解决方案咨询

问题原因

SQLite.NET 的 Where 方法接收的参数类型是 Expression<Func<T, bool>>,它会把传入的表达式树直接翻译为 SQL 语句执行。如果在表达式中调用自定义 C# 方法,SQLite.NET 的表达式解析器无法将自定义方法转换为对应的 SQL 语法,就会抛出 System.NotSupportedException 异常。

解决方案

方案1:封装为返回表达式树的方法(推荐)

将筛选逻辑直接封装为返回 Expression<Func<Intervention, bool>> 的静态方法,返回的表达式可以直接被 SQLite.NET 识别转换,代码如下:

private static Expression<Func<Intervention, bool>> ShouldInterventionBeConsideredInMonth(int month, int year)
{
    DateTime startOfMonth = new DateTime(year, month, 1).StartOfDay();
    DateTime endOfMonth = new DateTime(year, month, DateTime.DaysInMonth(year, month)).EndOfDay();

    return intervention => 
        // 先排除已删除数据
        !intervention.IsDeleted && 
        (
            // 有结束时间:时间段和当月重叠
            (intervention.EndDate != null && intervention.StartDate <= endOfMonth && intervention.EndDate >= startOfMonth)
            // 无结束时间:开始时间早等于当月月底
            || (intervention.EndDate == null && intervention.StartDate <= endOfMonth)
        );
}

调用时直接传入方法返回的表达式即可:

public async Task<IEnumerable<Intervention>> GetAMonthsInterventionsAsync(int month, int year)
{
    var interventions = await this.dataProviderService.GetAsync<Intervention>(
        ShouldInterventionBeConsideredInMonth(month, year),
        false);
    return interventions;
}

这种方案性能最优,所有筛选逻辑都在 SQL 层面执行,也实现了代码封装复用的需求。

方案2:表达式树拼接(适合多条件动态组合场景)

如果需要动态拼接多个筛选条件,可以自己实现表达式参数替换逻辑,或者使用轻量的表达式拼接工具类,将多个独立的筛选表达式合并为一个表达式传入 Where 方法。

方案3:内存过滤(仅适合小数据量场景)

如果筛选逻辑非常复杂,难以转换为表达式树,可以先将基础范围的数据查询到内存中,再用 Linq to Objects 执行自定义方法过滤:

// 原有返回bool的自定义方法不需要修改
private bool ShouldInterventionBeConsideredInMonth(int month, int year, Intervention intervention)
{
    DateTime startOfMonth = new DateTime(year, month, 1).StartOfDay();
    DateTime endOfMonth = new DateTime(year, month, DateTime.DaysInMonth(year, month)).EndOfDay();

    bool inMonth = false;
    if (intervention.StartDate <= endOfMonth && intervention.EndDate != null && intervention.EndDate >= startOfMonth)
    {
        inMonth = true;
    }
    else if (intervention.StartDate <= endOfMonth && intervention.EndDate == null)
    {
        inMonth = true;
    }
    if (intervention.IsDeleted)
    {
        inMonth = false;
    }
    return inMonth;
}

public async Task<IEnumerable<Intervention>> GetAMonthsInterventionsAsync(int month, int year)
{
    // 先查所有未删除的数据(可以加基础过滤减少返回数据量)
    var allInterventions = await this.dataProviderService.GetAsync<Intervention>(i => !i.IsDeleted, false);
    // 内存中执行自定义方法过滤
    var filtered = allInterventions.Where(i => ShouldInterventionBeConsideredInMonth(month, year, i));
    return filtered;
}

注意该方案会把所有符合基础条件的数据加载到内存,数据量大时性能会明显下降,不推荐生产环境大表使用。


内容的提问来源于stack exchange,提问作者Pat Long - Munkii Yebee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 09:24:02