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

.NET Core 2中纯ADO.NET用Lambda生成WHERE子句及相关方案咨询

刚好之前做过类似的需求,给你分享两个问题的实用解决方案:

一、用Lambda生成WHERE子句的现成工具/方案

你自己手写Expression解析确实容易踩坑还费时间,推荐用SqlKata这个轻量的SQL构建库,它完美支持Lambda表达式转WHERE条件,还自动处理参数化查询(避免SQL注入),完全不需要完整ORM的冗余功能,刚好匹配你的场景。

实现步骤:

  1. 先安装NuGet包:Install-Package SqlKata(或者根据你的数据库选对应的扩展包,比如SqlKata.SqlServer)
  2. 写通用的GetRecords方法:
using SqlKata;
using SqlKata.Compilers;
using System.Data.SqlClient;
using System.Linq.Expressions;

// 假设这是你的服务类
public class DataService
{
    private readonly string _connectionString;

    public DataService(string connectionString)
    {
        _connectionString = connectionString;
    }

    public IEnumerable<T> GetRecords<T>(Expression<Func<T, bool>> predicate)
    {
        // 根据你的数据库类型选择编译器,比如SqlServerCompiler/MySqlCompiler等
        var compiler = new SqlServerCompiler();
        // 假设实体类名和数据库表名一致,不一致的话可以加特性或者手动指定表名
        var query = new Query(typeof(T).Name).Where(predicate);
        
        // 编译生成带参数化的SQL和绑定参数
        var sqlResult = compiler.Compile(query);
        
        // 执行你的SQL读取逻辑(这里用SqlConnection示例,替换成你自己的连接方式)
        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            using (var reader = connection.ExecuteReader(sqlResult.Sql, sqlResult.Bindings))
            {
                // 这里替换成你自己的IDataReader到实体的映射逻辑
                return MapReaderToEntities<T>(reader);
            }
        }
    }

    // 示例:简单的手动映射方法,也可以用AutoMapper等工具简化
    private IEnumerable<T> MapReaderToEntities<T>(IDataReader reader) where T : new()
    {
        var properties = typeof(T).GetProperties();
        while (reader.Read())
        {
            var entity = new T();
            foreach (var prop in properties)
            {
                if (!reader.IsDBNull(reader.GetOrdinal(prop.Name)))
                {
                    prop.SetValue(entity, reader[prop.Name]);
                }
            }
            yield return entity;
        }
    }
}

这样你就可以像service.GetRecords<Person>(p => p.FirstName == "Jack" && p.City == "NY")这样调用,SqlKata会自动生成类似WHERE FirstName = @p0 AND City = @p1的参数化WHERE子句,安全又省心。

另外还有个备选方案是System.Linq.Dynamic.Core,它可以把Lambda表达式解析成字符串条件,但需要自己处理参数化,不如SqlKata直接。


二、IDataReader与IQueryable结合的思路

这里分两种场景:

1. 内存中对已读取的IDataReader数据进行IQueryable查询

如果IDataReader已经把数据从数据库拉到本地了,你可以先把数据转成IEnumerable<T>,再调用AsQueryable(),这样就能用Linq查询了:

using (var reader = connection.ExecuteReader(sql))
{
    var data = MapReaderToEntities<Person>(reader).AsQueryable();
    // 现在可以用IQueryable的各种方法
    var filtered = data.Where(p => p.Age > 30).OrderBy(p => p.LastName);
}

这种方式的缺点是查询是在内存中进行的,适合小数据集。

2. 数据库层面结合IQueryable与IDataReader(即先构建IQueryable再用IDataReader读取)

如果想让IQueryable的表达式树转换成SQL在数据库执行,然后用IDataReader读取结果,其实大部分Micro ORM都支持这个。比如用LinqToDB:

using LinqToDB;
using LinqToDB.Data;

public IQueryable<T> BuildQuery<T>(Expression<Func<T, bool>> predicate)
{
    using var dataContext = new DataConnection(_connectionString, new SqlServerProvider());
    return dataContext.GetTable<T>().Where(predicate);
}

// 执行查询并返回IDataReader
public IDataReader ExecuteQueryToReader<T>(IQueryable<T> query)
{
    var dataContext = ((IQueryable)query).Provider as DataContext;
    return dataContext.ExecuteReader(query.Expression);
}

LinqToDB会把IQueryable的表达式树编译成SQL,然后用IDataReader读取结果,兼顾了IQueryable的便捷和IDataReader的高性能。

如果不想用第三方库,自己实现IQueryProvider和IQueryable<T>也可以,但工作量很大,不推荐,除非有特殊定制需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:14:14