有没有一种方法可以使用the SQL Server 2012 Microsoft.SqlServer.Dac Namespace来确定数据库是否具有与DacPackage object所描述的模式相同的模式?我看过DacPackage和DacServices的API文档,但是没有运气。我错过了什么吗?
最佳答案
是的,自2012年以来,我一直在使用以下技术。
计算dacpac的指纹。
将该指纹存储在目标数据库中。
.dacpac只是一个zip文件,其中包含诸如元数据之类的好东西,并且
型号信息。
这是.dacpac中的屏幕抓图:
文件model.xml具有如下所示的XML结构
<DataSchemaModel>
<Header>
... developer specific stuff is in here
</Header>
<Model>
.. database model definition is in here
</Model>
</<DataSchemaModel>
我们需要做的是从
<Model>...</Model>
中提取内容并将其视为架构的指纹。
“可是等等!”你说。 “ Origin.xml具有以下节点:”
<Checksums>
<Checksum Uri="/model.xml">EB1B87793DB57B3BB5D4D9826D5566B42FA956EDF711BB96F713D06BA3D309DE</Checksum>
</Checksums>
以我的经验,此
<Checksum>
节点会更改,而与模型中的架构更改无关。因此,让我们开始吧。
计算dacpac的指纹。
using System.IO;
using System.IO.Packaging;
using System.Security.Cryptography;
static string DacPacFingerprint(byte[] dacPacBytes)
{
using (var ms = new MemoryStream(dacPacBytes))
using (var package = ZipPackage.Open(ms))
{
var modelFile = package.GetPart(new Uri("/model.xml", UriKind.Relative));
using (var streamReader = new System.IO.StreamReader(modelFile.GetStream()))
{
var xmlDoc = new XmlDocument() { InnerXml = streamReader.ReadToEnd() };
foreach (XmlNode childNode in xmlDoc.DocumentElement.ChildNodes)
{
if (childNode.Name == "Header")
{
// skip the Header node as described
xmlDoc.DocumentElement.RemoveChild(childNode);
break;
}
}
using (var crypto = new SHA512CryptoServiceProvider())
{
byte[] retVal = crypto.ComputeHash(Encoding.UTF8.GetBytes(xmlDoc.InnerXml));
return BitConverter.ToString(retVal).Replace("-", "");// hex string
}
}
}
}
现在有了这个指纹,用于应用dacpac的伪代码可以是:
void main()
{
var dacpacBytes = File.ReadAllBytes("<path-to-dacpac>");
var dacpacFingerPrint = DacPacFingerprint(dacpacBytes);// see above
var databaseFingerPrint = Database.GetFingerprint();//however you choose to do this
if(databaseFingerPrint != dacpacFingerPrint)
{
DeployDacpac(...);//however you choose to do this
Database.SetFingerprint(dacpacFingerPrint);//however you choose to do this
}
}