导读:本期聚焦于小伙伴创作的《Dapper怎么执行SQL脚本文件?批量执行SQL语句的完整教程》,敬请观看详情。把多个建表、初始化或迁移语句写进一个.sql文件后,用Dapper直接跑常常报错,因为默认只能执行单条命令。其实可以读取文件内容并按分隔符拆成多条语句,借助Transaction批量提交。本文说明如何用C#结合Dapper读取本地脚本、拆分GO分隔符、在事务中依次执行,并对比了逐条执行与整体事务提交的异同,也给出了处理注释与空行的思路,帮助你在控制台或Web项目里稳定地完成数据库初始化与批量更新。

在.NET项目里用Dapper访问数据库时,很多人习惯写单行SQL。但遇到数据库初始化、版本迁移或批量更新,往往要把一整段脚本放在.sql文件里。Dapper本身基于IDbConnection扩展,并不直接提供“跑脚本文件”的方法,需要我们自己读文件、拆语句、管事务。

Dapper怎么执行SQL脚本文件?批量执行SQL语句的完整教程

一、为什么Dapper不能直接执行脚本文件

Dapper的Execute方法本质上是对ADO.NET的封装,它把传入的字符串作为一条命令发给数据库驱动。大多数数据库(如SQL Server)在一条命令里不允许同时出现多个独立语句,除非用分号隔开且驱动支持。而常见的.sql脚本里会有GO这种批处理分隔符,它不是SQL语法,而是客户端工具(如SSMS)用来切分批次的标记,数据库驱动并不认识。

如果我们把含GO的整段文本直接丢给Execute,就会抛出“GO附近有语法错误”。因此,执行脚本文件的核心任务,是把文件内容按批处理规则拆成多条可独立执行的命令,再逐条或整体提交。

二、读取并拆分SQL脚本文件

最简单可靠的方式是按行读取,遇到单独一行的GO(忽略大小写与空格)就切断。下面示例用C#实现了一个基础拆分器,同时过滤空行和单行注释,避免把无意义内容发给数据库。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public static class SqlScriptSplitter
{
    // 按GO分隔符拆分脚本,返回多个批次命令
    public static List<string> SplitByGo(string filePath)
    {
        var batches = new List<string>();
        var current = new List<string>();

        foreach (var line in File.ReadAllLines(filePath))
        {
            // 去掉首尾空格后判断是否为GO批处理标记
            var trimmed = line.Trim();
            if (trimmed.Equals("GO", StringComparison.OrdinalIgnoreCase))
            {
                if (current.Count > 0)
                {
                    batches.Add(string.Join(Environment.NewLine, current));
                    current.Clear();
                }
            }
            else
            {
                // 跳过空行和--开头的注释行
                if (!string.IsNullOrWhiteSpace(trimmed) && !trimmed.StartsWith("--"))
                {
                    current.Add(line);
                }
            }
        }

        if (current.Count > 0)
        {
            batches.Add(string.Join(Environment.NewLine, current));
        }

        return batches.Where(b => !string.IsNullOrWhiteSpace(b)).ToList();
    }
}

上面的代码把脚本拆成了字符串列表,每个元素是一条可执行的批处理命令。如果脚本中没有GO,整文件会被当作一个批次。对于MySQL等使用分号分隔的数据库,可以把拆分逻辑改成按分号切,但要注意字符串内的分号不能误切,生产环境建议用成熟库如MariaDbBatch。

这种方式的优点是简单直观,不依赖第三方SQL解析器;缺点是无法处理跨行注释/* */和复杂嵌套。若你的脚本含有这类内容,可在读取阶段先用正则剔除块注释,再走行拆分逻辑。

三、用Dapper在事务中批量执行

拆出批次后,借助Dapper的Execute配合IDbTransaction,就能保证要么全成功要么全回滚。以下示例展示从文件读取到执行的全过程:

using System;
using System.Data.SqlClient;
using Dapper;

class Program
{
    static void Main()
    {
        var sqlFile = "init.sql";
        var connectionString = "Server=127.0.0.1;Database=test;User Id=sa;Password=123;";

        var batches = SqlScriptSplitter.SplitByGo(sqlFile);

        using (var conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (var tx = conn.BeginTransaction())
            {
                try
                {
                    foreach (var batch in batches)
                    {
                        // Dapper执行单条批处理命令
                        conn.Execute(batch, transaction: tx);
                    }
                    tx.Commit();
                    Console.WriteLine("脚本执行完成");
                }
                catch (Exception ex)
                {
                    tx.Rollback();
                    Console.WriteLine("执行失败:" + ex.Message);
                }
            }
        }
    }
}

这里把拆分和执行分开,逻辑清晰。事务包裹了所有批次,任何一条失败都会整体回滚,适合初始化场景。如果脚本只是日常批量更新且允许部分成功,也可以去掉事务,逐条执行并记录错误,但初始化类操作强烈建议用事务。

需要注意的是,conn.Execute的第二个参数通常用来传匿名对象做参数化,本例直接传transaction命名参数,语法上没问题。若批次里含有参数化占位符,则要在循环内构造对应对象,而不能把不同结构的参数混在一起。

四、与逐条Execute的对比

有些开发者图省事,会在Execute里用分号拼一大串SQL,而非读文件。下面用表格列出两种思路的差异:

方式可维护性错误处理适用场景
读取.sql文件并拆分高,脚本独立于代码事务内统一回滚迁移、初始化、复杂批处理
代码内拼多语句低,SQL散落在C#中需手动截段捕获简单固定小批量

从长期看,把SQL脚本作为独立资源文件(如放在项目Sql目录,设置生成操作为嵌入资源或复制至输出目录)更利于版本管理。Dapper只负责执行,不负责存逻辑,这种职责划分也让测试更方便:你可以单独对脚本做语法检查。

另外,在Web应用里执行大脚本要留意连接超时。可在连接字符串加Connection Timeout=300,或在执行前conn.Execute("SET LOCK_TIMEOUT 300000"),避免默认几十秒超时被中断。

五、常见误区与小结

一个典型误区是认为Dapper有类似ExecuteScript的内置方法。实际上官方只提供基础Execute,脚本处理能力要自己写。另一个误区是忽略GO只属于客户端工具,把它当SQL发给数据库。只要记住“读文件、按批拆、事务包”这三步,就能用Dapper稳妥地跑任意SQL脚本文件。

实践中建议把拆分器做成通用工具类,支持GO与分号双模式,并在执行前打印批次数,方便排查。这样无论是本地控制台还是服务端启动迁移,都能复用同一套逻辑,减少数据库操作带来的意外停机。

DapperSQL脚本文件批量执行SQL修改时间:2026-08-01 05:03:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。