我正在创建一个在 dbup 中实现 IScriptProvider 接口的自定义 ScriptProvider,并且我能够使用该GetScripts()
方法获取脚本列表,并返回一个SqlScript
对象。我想先编译对象,然后在返回之前修改每个脚本的名称,将当前版本添加到插入到日志表中的文件名之前。
我的理解是这应该是可行的,因为脚本的内容在SqlScript
填充时已经添加到对象中,似乎此时修改名称不会影响任何事情。
我遇到的问题是Name
SqlScript 对象的属性是只读的,所以我不能随意修改它。
我该如何解决这个问题,或者是否有另一种方法可以编译要执行和记录的脚本,然后在将脚本名称写入日志表之前,为脚本名称添加一个值。
例如,Script001
变成Release 1.0.0 - Script001
。
在读取先前执行的脚本时,我还需要能够删除此值,以确保它们与实际文件名匹配并且不会再次执行。
更新
namespace DbUpManifest
{
public class DeploymentManifestScriptProvider : IScriptProvider
{
readonly string directoryPath;
readonly string basePath;
readonly Func<string, bool> filter;
readonly Encoding encoding;
readonly FileSystemScriptOptions options;
public string Release;
public List<string> FileList;
public DeploymentManifestScriptProvider(string basePath, string directoryPath, FileSystemScriptOptions options)
{
if (options == null)
throw new ArgumentNullException("options");
this.options = options;
this.directoryPath = directoryPath;
this.basePath = basePath;
}
private List<string> SerializeJsonFile()
{
Manifest manifest;
var files = new List<string>();
using (StreamReader file = File.OpenText(directoryPath))
{
JsonSerializer serializer = new JsonSerializer();
manifest = (Manifest)serializer.Deserialize(file, typeof(Manifest));
}
Release = manifest.Release.ToString();
foreach (var item in manifest.Scripts)
{
string thisItem;
if(Debugger.IsAttached)
{
thisItem = string.Concat(basePath, @"Deployment Scripts\vNext\", item);
}
else
{
thisItem = string.Concat(basePath, @"Deployment Scripts\", Release, @"\", item);
}
FileAttributes attr = File.GetAttributes(thisItem);
foreach (var scriptExtension in options.Extensions)
{
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
{
files.AddRange(Directory.GetFiles(thisItem, scriptExtension, ShouldSearchSubDirectories()));
}
else
{
files.Add(thisItem.ToString());
}
}
}
foreach (var item in manifest.StoredProcedures)
{
string thisItem = string.Concat(basePath, "Stored Procedures", "\\", item);
FileAttributes attr = File.GetAttributes(thisItem);
foreach (var scriptExtension in options.Extensions)
{
files.Add(thisItem.ToString());
}
}
return files;
}
public IEnumerable<SqlScript> GetScripts(IConnectionManager connectionManager)
{
List<string> scripts = SerializeJsonFile();
var outputFiles = scripts.Select(x => SqlScript.FromFile(x))
.OrderBy(x => x.Name)
.ToList();
return outputFiles;
}
SearchOption ShouldSearchSubDirectories()
{
return options.IncludeSubDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
}
}
}
我已经尝试修改它以将发布添加到文件名,但是它错误地说它找不到文件,因为物理文件实际上没有以前面的字符串命名。
var outputFiles = scripts.Select(x => SqlScript.FromFile(String.Concat(Release," - ", x)))
.OrderBy(x => x.Name)
.ToList();
我最终希望有一个清单文件,将部署脚本作为“运行一次”类型的脚本运行,然后我想维护一个单一版本的东西,例如存储的过程和视图,并让清单文件指示哪些脚本可以运行每个部署,所以我们不会删除和重新创建每个存储的过程,这就是我们目前正在做的事情。
问题是,我可以选择使用 NullJournal 而不向数据库写入任何内容,或者存储的过程不会执行多次,因为它们的名称总是相同的。
也试图想其他方法来实现这一点,但到目前为止我一无所获。
在一个完美的世界中,我希望能够将物理文件dbo.StoredProcedure.sql
记录为Release 1.0.0 - dbo.StoredProcedure.sql
. 这样,如果该存储过程在未来发生变化,它将被执行并存储为Release 2.0.0 - dbo.StoredProcedure.sql
它所在的任何版本。但物理文件始终只有一个跨时间/版本的同名文件。