惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
罗磊的独立博客
F
Fortinet All Blogs
人人都是产品经理
人人都是产品经理
量子位
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
B
Blog RSS Feed
腾讯CDC
博客园_首页
aimingoo的专栏
aimingoo的专栏
博客园 - 三生石上(FineUI控件)
博客园 - Franky
S
SegmentFault 最新的问题
N
Netflix TechBlog - Medium
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LINUX DO - 热门话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler
D
Docker
P
Privacy & Cybersecurity Law Blog
S
Securelist
V
V2EX
Jina AI
Jina AI
阮一峰的网络日志
阮一峰的网络日志
T
Tor Project blog
The Hacker News
The Hacker News
Microsoft Azure Blog
Microsoft Azure Blog
AWS News Blog
AWS News Blog
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
T
The Exploit Database - CXSecurity.com
Help Net Security
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 叶小钗
Recent Announcements
Recent Announcements
Cloudbric
Cloudbric
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Latest news
Latest news
MongoDB | Blog
MongoDB | Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recorded Future
Recorded Future
V2EX - 技术
V2EX - 技术

博客园 - BloggerSb

Swagger 文档设置api版本 .Net Core Routing Demo .net Core读取配置比较 大文件单词统计 (编程题) ASP.NET Core CRUD API 创建 UserController,实现 Get, Post, Put, Delete 方法,使用 EF Core 访问数据库。 (编程题) 设计模式落地:Repository + UnitOfWork + CQRS 完整实现 (编程题) 给定百万级订单表,实现高效分页 + 动态条件查询 + 导出 Excel(避免内存爆炸) (编程题) 实现一个带 CorrelationId、请求日志、异常统一处理的中间件链 (编程题) 异步限流器实现(编程题) 编程题,记录所有接口的执行耗时 .net面试题目 (问答题) 面试高频简答题 Aspose最新Slides破解 HttpContext.User.Identity.IsAuthenticated 为false 关于Cannot resolve scoped service from root provider解决方案 MongoDB用户权限管理,设置密码并连接 mongodb连接字符串 mongodb 使用 MongoDB Compass 创建账号,角色 安装mongodb bootstrap popover 设置悬浮框宽度 div contenteditable="true" 添加placehoder效果 光标自动定位到起始位置contenteditable="true" ,v-html绑定内容,div可编辑时,光标移到最前面
简化版DbExecutor,将DataTable映射到T属性(支持Dapper风格的匿名参数)。(编程题)
BloggerSb · 2026-04-17 · via 博客园 - BloggerSb

手写一个简化版DbExecutor,支持Query<T>(string sql, object parameters),将DataTable映射到T属性(支持Dapper风格的匿名参数)。

· 考察点:反射/Emit/表达式树性能对比、缓存映射逻辑、IDbCommand参数化注入。

public class DbExecutor
{
    private readonly string _connectionString;
    // 缓存类型映射委托,避免频繁反射
    private readonly ConcurrentDictionary<Type, Func<IDataRecord, object>> _mapperCache;

    public DbExecutor(string connectionString)
    {
        _connectionString = connectionString;
        _mapperCache = new ConcurrentDictionary<Type, Func<IDataRecord, object>>();
    }

    // 执行查询,返回T类型列表
    public async Task<List<T>> QueryAsync<T>(string sql, object parameters = null)
    {
        var result = new List<T>();
        // 获取类型映射委托(缓存,避免重复反射)
        var mapper = _mapperCache.GetOrAdd(typeof(T), CreateMapper<T>);

        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();

        // 处理参数
        using var command = new SqlCommand(sql, connection);
        if (parameters != null)
        {
            // 反射获取参数对象的属性,添加到SqlCommand
            var paramProperties = parameters.GetType().GetProperties();
            foreach (var prop in paramProperties)
            {
                var value = prop.GetValue(parameters) ?? DBNull.Value;
                command.Parameters.AddWithValue($"@{prop.Name}", value);
            }
        }

        // 执行查询,映射结果
        using var reader = await command.ExecuteReaderAsync();
        while (await reader.ReadAsync())
        {
            var item = (T)mapper(reader);
            result.Add(item);
        }

        return result;
    }

    // 创建类型映射委托(使用Expression树,提升性能)
    private Func<IDataRecord, object> CreateMapper<T>(Type type)
    {
        // 创建参数(IDataRecord)
        var parameter = Expression.Parameter(typeof(IDataRecord), "record");
        var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        var bindings = new List<MemberBinding>();

        foreach (var prop in properties)
        {
            // 获取列名(支持[Column]特性,无特性则使用属性名)
            var columnAttr = prop.GetCustomAttribute<ColumnAttribute>();
            var columnName = columnAttr?.Name ?? prop.Name;

            // 表达式:record[columnName]
            var indexExpr = Expression.Property(parameter, "Item", Expression.Constant(columnName));
            // 转换类型(将object转换为属性类型)
            var convertExpr = Expression.Convert(indexExpr, prop.PropertyType);
            // 绑定到属性
            var binding = Expression.Bind(prop, convertExpr);
            bindings.Add(binding);
        }

        // 表达式:new T { Prop1 = ..., Prop2 = ... }
        var newExpr = Expression.New(type);
        var initExpr = Expression.MemberInit(newExpr, bindings);
        // 转换为object
        var convertToObject = Expression.Convert(initExpr, typeof(object));
        // 编译为委托
        return Expression.Lambda<Func<IDataRecord, object>>(convertToObject, parameter).Compile();
    }
}

// 辅助特性:用于指定数据库列名
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute
{
    public string Name { get; }

    public ColumnAttribute(string name)
    {
        Name = name;
    }
}