SQL 脚本运行器






4.69/5 (13投票s)
一个简单的控制台应用程序,用于执行由开发人员添加的所有 SQL 文件,这些开发人员使用分散式开发环境。
引言
一个简单的控制台应用程序,用于执行由开发人员添加的所有 SQL 文件,这些开发人员使用分散式开发环境。
背景
您如何在分散式开发环境中管理 SQL 脚本?
下图大体描述了我心中分散式开发环境的概念?
图 1
集中式开发环境只有集中的数据存储。
分散式开发环境是拥有本地存储的那种——虚线框。
在分散式环境中,通常有一个主数据库,每个开发人员都有自己的本地副本。这种开发环境允许独立工作,无需网络连接;如果主存储出现问题,其他人仍然可以与他们的本地数据库副本一起工作。
- 应该是可配置的——应该指定 SQL 脚本文件夹。
- 可执行文件应该按顺序运行脚本。
- 如果脚本存在语法错误,应用程序应该在运行脚本之前显示它——验证。
- 如果脚本存在运行时错误,所有脚本都应该回滚。应显示错误发生的文件和行号。
- 如果没有错误,则所有脚本都将执行并应用更改。
- 应该有一种方法来测试结果——简单的单元测试。
使用代码 - 实现
返回 SQL 文件列表
目录及其子目录中的所有文件都应返回,但顺序正确——这意味着 Ver11.0 文件夹中的文件不应排在 Ver1.0 之后,如果存在 Ver2.0 文件夹。这意味着排序顺序应基于版本的值,而不是字符串值。
这很容易通过 LINQ 表达式实现
foreach (var d in Directory.GetDirectories(dir).OrderBy(x => float.Parse(Path.GetFileName(x).Substring(Configuration.Configuration.Pproperties.ScriptVersionPrefix.Length)))) {
显示执行百分比
当使用 \r 时,光标会回到当前行的开头,然后可以重写。
Console.Write("\r{0}{1}% complete", message, percent);
如何查找 SQL 编译时错误?
为此使用了 SQL Server Management Studio 的解析功能。我使用了两个程序集:Microsoft.Data.Schema.ScriptDom; Microsoft.Data.Schema.ScriptDom.Sql;
这两个程序集可以在以下位置找到:C:\Windows\Microsoft.NET\assembly\GAC_MSIL
如果您已安装 MS SQL Management Studio
public static bool ParseSqlFile(string file) { IList<ParseError> errors = new List<ParseError>(); bool hasErros = false; using (TextReader reader = File.OpenText(file)) { var parser = new TSql100Parser(true); var script = parser.Parse(reader, out errors) as TSqlScript; hasErros = errors.Count > 0; foreach (var parseError in errors) { Errors.ProcessErrors(file, parseError); } } return hasErros; }
应用程序的主方法
所有内容都在主方法中集成。在这里,在打开数据库连接后,SQL 文件将在一个集合中返回,然后对每个文件,其 SQL 脚本都会被解析并作为事务的一部分执行,以便在执行不成功时数据可以回滚。
请注意
//TODO: remove Thread.Sleep(500);
这在实际使用中应该被移除。它对演示很有用,以便可以看到执行百分比。
下一节与当前项目无关,可以跳过。如果您在获取源代码后不理解其中的任何内容,可以回顾一下。
以 OOP 方式获取配置
在“Configuration”文件夹中可以找到三个文件,它们负责以 OOP 方式从 App.config 获取配置设置。一个自定义属性定义了设置的键,然后该属性应用于一个属性,该属性在控制台应用程序启动时通过反射进行设置。
自定义属性类
[AttributeUsage(AttributeTargets.Property, Inherited = false)] class ConfigAttribute : Attribute { /// <summary> /// The key /// </summary> private readonly string key; Class with properties which have attributes of the custom attrubute type public class ConfigProperties { /// <summary> /// Gets or sets a value indicating whether [use AU s_ AIS]. /// </summary> /// <value> /// <c>true</c> if [use AU s_ AIS]; otherwise, <c>false</c>. /// </value> [Config("SQLDir")] public string SqlDir { get; set; }
在“Configuration.cs”文件中,通过反射读取属性。
static Configuration() { properties = new ConfigProperties(); var props = typeof(ConfigProperties).GetProperties(); foreach (PropertyInfo prop in props) { string auth = string.Empty; object[] attrs = prop.GetCustomAttributes(true); foreach (object attr in attrs) { var authAttr = attr as ConfigAttribute; if (authAttr != null) { string propName = prop.Name; auth = authAttr.Key; } try { var value = Convert.ChangeType(ConfigurationManager.AppSettings.Get(auth), prop.PropertyType); prop.SetValue(properties, value, null); } catch (Exception ex) { throw ex; } break; } } }