DacFx/SSDT public model #1. DAC package

image

Сегодня я хочу немного рассказать о концепции (слово громкое, но почему-то другого не приходит на ум с ходу) Data-tier Applications.

А точнее об инструментах для её реализации DACFx и Microsoft SQL Server Data Tools (SSDT). А если еще точнее – о части возможностей по расширению этих инструментов. Улыбка

Но давайте все по порядку…

Что такое DACFx и SSDT?

DACFx – это набор инструментов для управление развертыванием баз данных для SQL Server или SQL Azure (т.е. “SQL Server в облаке”).

SSDT – это расширение для Visual Studio (начиная с VS 2010, но последние версии обновляются уже только для VS 2013), которое позволяет разрабатывать, отлаживать, тестировать, и т.д. код для SQL Server (это может быть как T-SQL код, так и .Net, т.е. SQLCLR код).

image

Т.е., по большому счету SSDT является наследником Database projects, которые были в Visual Studio, если не ошибаюсь, с 2008 версии. Причем вы получаете сразу кучу плюсов в одном флаконе: подсказки к коду, отладка, работа с планами запросов, поддержка проектов (т.е. контроль версий, сборка, тестирование, …)

Следующий вопрос – как связаны между собой DacFx, SQL Server, SSDT? А собственно вот так:

image

Центральным звеном этой системы является так называемый DAC-пакет (DACPAC) – это по сути дистрибутив развертываемой базы, который содержит в себе информацию обо всех объектах базы: таблицах, вьюхах, хранимых процедурах, дополнительных скриптах (которые выполняются только в момент деплоя), сборках SQLCLR и т.д.

Остальные участники приведенной схемы всячески используют этот пакет:

  • Результатом компиляции проекта в SSDT является DAC-пакет (плюс пакеты можно использовать в обратном направлении – как источник: экспортировать из них объекты в проект или подключать их как references – в последнем случае, например, можно подключить DAC-пакет базы master и получить подсказку по коду для кучи системных ХП, View и таблиц)
  • DacFx поставляется вместе с SQL Server (начиная, если не ошибаюсь, с 2008-го сервера) + его можно установить отдельно (если нужна более новая версия или если нужно делать удаленную установку – например, для SQL Azure) и обеспечивает следующие команды:
DEPLOY Развернуть базу
EXTRACT Выгрузить объекты базы (но не данные!) в DAC-пакет
REGISTER Зарегистрировать существующую базу как data-tier application (это можно также сделать в момент деплоя). Такая регистрация даёт некоторые дополнительные возможности:

  • возможность контролировать какая версия пакета установлена
  • какие вносились изменения в базу (например, добавлялись индексы или менялись ХП) с момента развертывания DAC-пакета
UNREGISTER Разрегистрировать data-tier application. Все DAC-метаданные будут удалены, а база станет обычной базой
UPGRADE Обновить установленную базу или data-tier application (поддерживаются оба варианта)
EXPORT Похожа на EXTRACT, но помимо схемы выгружаются и данные из таблиц. Кроме того, пакет будет иметь другое расширение: .bacpac.
IMPORT Развертывание сохраненного .bacpac

Вызывать эти операции можно через:

  • UI SSMS
  • консольную утилиту SqlPackage.exe, которая идет в поставке DACFx
  • UI Visual Studio
  • MSBuild (это для случая, когда деплой делается прямо в процессе сборки)
  • Management Portal for SQL Azure
  • Web Deploy (т.е. одновременно с развертыванием сайта, можно развернуть и базу к нему)
  • Свой код

Вот, например, так выглядит строка деплоя базы Northwind через SqlPackage.exe:

sqlpackage 
   /a:publish 
   /sf:Northwind.dacpac
   /tcs:"Data Source=(local);Integrated Security=True;Initial Catalog=Northwind"

 

Для каких версий это работает и как там с совместимостью?

Говоря о совместимости, нужно сказать в первую очередь следующее: для DACFx и SSDT при переходе с версии 2.0 на 3.0 была нарушена совместимость. Обновление было выпущено в октябре 2012 года и соответственно новые версии DACFx не могут работать с пакетами созданными в ранних версиях DACFx и SSDT, и наоборот – старые не работают с новыми.

Изменения коснулись как формата пакета, так и API.

Какие здесь рекомендации:

  • с практически 100% вероятностью, если вы ставите обновления SSDT (о которых сообщает Extensions and Updates Manager студии), то даже на Visual Studio 2010 вы будете работать c версией SSDT, которая генерирует пакеты в формате 3.0
  • соответственно, если вам необходимо ставить пакеты на SQL Server более ранних версий, вам следует установить Data-Tier Application Framework самостоятельно.

Собственно, найти Data-Tier Application Framework можно на сайте MSDN Downloads. Например, на текущий момент это можно сделать по ссылке Microsoft® SQL Server® Data-Tier Application Framework (April 2014).

Только обратите внимание, что этот пакет требует также установки Microsoft SQL Server System CLR Types (SQLSysCLRTypes.msi) и Microsoft SQL Server Transact-SQL ScriptDom (SQLDOM.msi). Их можно найти по ссылке Microsoft® SQL Server® 2014 Feature Pack.

Теперь можно переходить непосредственно к изучению “внутренностей” DACFx

Что представляет собою DAC пакет?

По своему формату, это Open Packaging Conventions (OPC) файл, в котором, судя по всему, все компоненты имеют фиксированные имена, а связи не используются. Впрочем, последний факт нам будет интересен только при условии, что мы захотим читать или править пакет “руками”, а не через DACFx.

Что обычно (“обычно”, т.к. как мы увидим далее, в DACPAC можно помещать и свои собственные компоненты, которые затем будут использоваться при деплое)?

image

Самое основное, это, несомненно, модель базы. Представляет она собой XML, приблизительно такого вида:

<?xml version="1.0" encoding="utf-8"?>
<DataSchemaModel FileFormatVersion="1.2" 
	SchemaVersion="2.4" 
	DspName="Microsoft.Data.Tools.Schema.Sql.Sql120DatabaseSchemaProvider" 
	CollationLcid="1033" 
	CollationCaseSensitive="False" 
	xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">
  <Header>
    <CustomData Category="AnsiNulls">
      <Metadata Name="AnsiNulls" Value="True" />
    </CustomData>
    <CustomData Category="QuotedIdentifier">
      <Metadata Name="QuotedIdentifier" Value="True" />
    </CustomData>
    <CustomData Category="CompatibilityMode">
      <Metadata Name="CompatibilityMode" Value="120" />
    </CustomData>
    <CustomData Category="Reference" Type="Assembly">
      <Metadata Name="LogicalName" Value="SampleDB.dll" />
      <Metadata Name="FileName" Value="...\SAMPLEDB.DLL" />
      <Metadata Name="AssemblyName" Value="SampleDB" />
      <Metadata Name="PermissionSet" Value="SAFE" />
      <Metadata Name="Owner" Value="" />
      <Metadata Name="GenerateSqlClrDdl" Value="True" />
      <Metadata Name="IsVisible" Value="True" />
      <Metadata Name="IsModelAware" Value="True" />
      <Metadata Name="SkipCreationIfEmpty" Value="True" />
      <Metadata Name="AssemblySymbolsName" Value="...\SampleDB.pdb" />
    </CustomData>
    <CustomData Category="SqlCmdVariables" Type="SqlCmdVariable" />
  </Header>
  <Model>
    <Element Type="SqlDatabaseOptions">
      <Property Name="Collation" Value="SQL_Latin1_General_CP1_CI_AS" />
      <Property Name="IsAnsiNullDefaultOn" Value="True" />
      <Property Name="IsAnsiNullsOn" Value="True" />
      <Property Name="IsAnsiWarningsOn" Value="True" />
      <Property Name="IsArithAbortOn" Value="True" />
      <Property Name="IsConcatNullYieldsNullOn" Value="True" />
      <Property Name="IsTornPageProtectionOn" Value="False" />
      <Property Name="IsFullTextEnabled" Value="True" />
      <Property Name="PageVerifyMode" Value="3" />
      <Property Name="DefaultLanguage" Value="" />
      <Property Name="DefaultFullTextLanguage" Value="" />
      <Relationship Name="DefaultFilegroup">
        <Entry>
          <References ExternalSource="BuiltIns" Name="[PRIMARY]" />
        </Entry>
      </Relationship>
    </Element>
    <Element Type="SqlPrimaryKeyConstraint">
      <Relationship Name="ColumnSpecifications">
        <Entry>
          <Element Type="SqlIndexedColumnSpecification">
            <Relationship Name="Column">
              <Entry>
                <References Name="[dbo].[Table1].[Id]" />
              </Entry>
            </Relationship>
          </Element>
        </Entry>
      </Relationship>
      <Relationship Name="DefiningTable">
        <Entry>
          <References Name="[dbo].[Table1]" />
        </Entry>
      </Relationship>
      <Annotation Type="SqlInlineConstraintAnnotation" Disambiguator="3" />
    </Element>
    <Element Type="SqlTable" Name="[dbo].[Table1]">
      <Property Name="IsAnsiNullsOn" Value="True" />
      <Relationship Name="Columns">
        <Entry>
          <Element Type="SqlSimpleColumn" Name="[dbo].[Table1].[Id]">
            <Property Name="IsNullable" Value="False" />
            <Relationship Name="TypeSpecifier">
              <Entry>
                <Element Type="SqlTypeSpecifier">
                  <Relationship Name="Type">
                    <Entry>
                      <References ExternalSource="BuiltIns" Name="[int]" />
                    </Entry>
                  </Relationship>
                </Element>
              </Entry>
            </Relationship>
            <AttachedAnnotation Disambiguator="3" />
          </Element>
        </Entry>
        <Entry>
          <Element Type="SqlSimpleColumn" Name="[dbo].[Table1].[Name]">
            <Relationship Name="TypeSpecifier">
              <Entry>
                <Element Type="SqlTypeSpecifier">
                  <Property Name="IsMax" Value="True" />
                  <Relationship Name="Type">
                    <Entry>
                      <References ExternalSource="BuiltIns" Name="[nvarchar]" />
                    </Entry>
                  </Relationship>
                </Element>
              </Entry>
            </Relationship>
          </Element>
        </Entry>
      </Relationship>
      <Relationship Name="Schema">
        <Entry>
          <References ExternalSource="BuiltIns" Name="[dbo]" />
        </Entry>
      </Relationship>
    </Element>
  </Model>
</DataSchemaModel>
Как видите, схема содержит структурированное описание содержимого базы, а также различных её параметров. В приведенном примере мы имеем дело с очень простой моделью, которая включает:
  • Схему dbo
  • Таблицу Table1 со столбцами Id и Name
  • Primary key сonstraint, наложенный на столбец Id

Понятно, что полностью структурировать можно далеко не любые объекты. Например код хранимой процедуры останется кодом. Однако, вполне можно получить много других интересных данных. Вот к примеру код процедуры

CREATE PROCEDURE CustOrdersOrders @CustomerID nchar(5)
AS

SELECT OrderID,	
		OrderDate, 
		RequiredDate, 
		ShippedDate

FROM Orders

WHERE CustomerID = @CustomerID

ORDER BY OrderID

В модели он будет представлен вот таким тэгом:

<Element Type="SqlProcedure" Name="[dbo].[CustOrdersOrders]">
  <Property Name="BodyScript">
    <Value QuotedIdentifiers="True" AnsiNulls="True">
      <![CDATA[
SELECT OrderID, 
	OrderDate,
	RequiredDate,
	ShippedDate
FROM Orders
WHERE CustomerID = @CustomerID
ORDER BY OrderID]]>
    </Value>
  </Property>
  <Property Name="IsAnsiNullsOn" Value="True" />
  <Relationship Name="BodyDependencies">
    <Entry>
      <References Name="[dbo].[Orders]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[Orders].[OrderID]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[Orders].[OrderDate]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[Orders].[RequiredDate]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[Orders].[ShippedDate]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[Orders].[CustomerID]" />
    </Entry>
    <Entry>
      <References Name="[dbo].[CustOrdersOrders].[@CustomerID]" />
    </Entry>
  </Relationship>
  <Relationship Name="Parameters">
    <Entry>
      <Element Type="SqlSubroutineParameter" 
                   Name="[dbo].[CustOrdersOrders].[@CustomerID]">
        <Relationship Name="Type">
          <Entry>
            <Element Type="SqlTypeSpecifier">
              <Property Name="Length" Value="5" />
              <Relationship Name="Type">
                <Entry>
                  <References ExternalSource="BuiltIns" Name="[nchar]" />
                </Entry>
              </Relationship>
            </Element>
          </Entry>
        </Relationship>
      </Element>
    </Entry>
  </Relationship>
  <Relationship Name="Schema">
    <Entry>
      <References ExternalSource="BuiltIns" Name="[dbo]" />
    </Entry>
  </Relationship>
  <Annotation Type="SysCommentsObjectAnnotation">
    <Property Name="CreateOffset" Value="2" />
    <Property Name="Length" Value="184" />
    <Property Name="StartLine" Value="1" />
    <Property Name="StartColumn" Value="1" />
    <Property Name="HeaderContents" 
          Value="
CREATE PROCEDURE CustOrdersOrders @CustomerID nchar(5)
AS" />
  </Annotation>
</Element>

Как видите, тело процедуры осталось как было, зато была извлечена информация о:

  • параметрах процедуры
  • привязке к схеме
  • связанных (использованных в процедуре) объектах – таблице и столбцах

Так что уже есть материал для анализа.

Следующий важный элемент DAC-пакета, это компоненты с метаданными. Это тоже XML примерно такого вида:

DacMetadata.xml

<?xml version="1.0" encoding="utf-8"?>
<DacType xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">
  <Name>Northwind</Name>
  <Version>1.0.0.0</Version>
</DacType>

Origin.xml

<?xml version="1.0" encoding="utf-8"?>
<DacOrigin xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">
  <PackageProperties>
    <Version>3.0.0.0</Version>
    <ContainsExportedData>false</ContainsExportedData>
    <StreamVersions>
      <Version StreamName="Data">2.0.0.0</Version>
      <Version StreamName="DeploymentContributors">1.0.0.0</Version>
    </StreamVersions>
  </PackageProperties>
  <Operation>
    <Identity>88bd7153-a625-4b70-90ef-7fcf44bfe710</Identity>
    <Start>2015-01-21T11:56:20.2689248+04:00</Start>
    <End>2015-01-21T11:56:20.4529211+04:00</End>
    <ProductName>Microsoft.Data.Tools.Schema.Tasks.Sql, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</ProductName>
    <ProductVersion>12.0.41025.0</ProductVersion>
    <ProductSchema>http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02</ProductSchema>
  </Operation>
  <Checksums>
    <Checksum Uri="/model.xml">F470243A438C1D86A4281C59C3B835B92BED61D7C05ACF933040CFC7384EA501</Checksum>
  </Checksums>
</DacOrigin>

Первый содержит лишь имя и версию Data tier приложения, которое включено в пакет.

А вот второй – куда интереснее… В нем, в частности, содержится описание того, что включено в пакет (например, включены ли данные, т.е. по сути – является ли данный пакет BACPAC-ом), что требуется для его развертывания (в текущем примере только версия SQL сервера и assembly, которая выполняет разворачивания, а в целом, здесь будет появляться информация обо всех расширениях deploy-процесса, которые требуются пакету).

Ну и наконец, в пакете содержатся:

  • Pre- и Post- деплойные скрипты, т.е. SQL код, который выполняется до или после процесса деплоя
  • Refactor log – XML-компонент, который описывает все переименования, сделанные в модели.

Продолжение следует…

This entry was posted in Разработка ПО and tagged , , , . Bookmark the permalink.

7 Responses to DacFx/SSDT public model #1. DAC package

  1. xvhd says:

    Доброго времени суток Роман.
    Представте что развалится база в пару десятков Гигобайт бухгалтерии, что делать будем ?.

    • Спасать. 😉
      Вот только DACFx тут не поможет ничем.

      P.S. И все же Михаил

      • xvhd says:

        Да ,не то слово ,даже при такой ситуации незнаю ,в облаке же развал будет ,пока перекачаем 20 Гб ,а еще на живую ,кочмарь.

        • Ну нормальных облачных провайдеров уже есть средства для бэкапирования прямо в облаке. Но кроме того, что они есть я сказать ничего не могу 😃 Не моя область.

          • xvhd says:

            Да тут порой после рестайлинг (патчей) базы как виноград по осени сыпятся. Особенно более 10 Гб весом ,откаты не помогут когда отчетность горит ,нужно как минимум время (перерыв в сдаче) а если это санаторий ? Там по 1000 отчетов бахают в раз ,и тут представте она упала ;( развалилась и бух (весь отдел который с ней /базой работает в панике .

  2. xvhd says:

    Поостите ;Михаил. Зачитался😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s