运行 SQL 使用特定于 Azure 的功能时本地服务器数据库?

Running SQL Server database locally when using Azure-specific functionality?

我正在考虑将使用本地 SQL 服务器的项目迁移到 SQL Azure。数据库具有跨数据库依赖性,其中某些视图引用同一服务器上的另一个数据库,SQL Azure 不支持。

我已成功修改这些以使用外部表,这些外部表使用使用以下内容创建的外部数据源:

CREATE EXTERNAL DATA SOURCE [MyExternalDataSource] WITH
(
    TYPE = RDBMS,
    LOCATION = 'SqlServerName',
    DATABASE_NAME = 'SqlServerDatabaseName',
    CREDENTIAL = cred
);

但是,此类数据源使用的 RDBMS 类型似乎仅受 SQL Azure 支持,而非本地 SQL 服务器。 运行 这个针对前者的脚本可以正常工作,而后者会导致抛出以下错误:

Incorrect syntax near 'RDBMS'

因此,这意味着解决方案中的数据库项目不能同时用于 Azure SQL 和本地 SQL 服务器安装。

作为解决方法,我正在考虑以下选项,但每个选项都有其缺点:

  1. 解决方案中有多个数据库项目,一个针对 SQL Azure,另一个针对 SQL 服务器 - 虽然这意味着将任何数据库更新复制到两个项目。

  2. 从使用外部表改为使用 Azure 提供的数据同步功能,并在两个数据库中复制表和数据(消除使用导致问题的外部数据源的需要)-虽然这有至少 5 分钟的延迟(在这种特定情况下可能是可以接受的,但肯定不是每个人都可以接受)

其他开发人员如何处理这种 SQL 需要在您的项目中使用 Azure 特定功能但您还需要能够 运行 的本地副本的场景数据库也用于开发?

您可以尝试创建3个项目:
1. 项目仅包含定义为视图的特定于 Azure 的引用。
2. 项目仅包含 SQL 定义为视图的服务器特定引用。视图的结构应该相同。
3. 你的主要项目。在这个项目中,您将引用之前的其中一个作为 "composite project" 参考。
https://docs.microsoft.com/en-us/sql/ssdt/add-database-reference-dialog-box?view=sql-server-2017

这里概述了几种方法: Conditional logic in PostDeployment.sql script using SQLCMD

在尝试了所有选项后,对我有用的是使用构建事件。

使用这种方法,我将项目设置为使用一个空脚本作为预部署脚本,然后在构建之前将其替换为正确的脚本(针对 On-Premises 的调试和针对 Azure 的发布)。构建后,占位符脚本被复制回来,以避免将更改的文件提交给源代码管理。

文件夹结构如下:

在项目文件中,我添加了以下 BeforeBuild 和 AfterBuild 目标:

<Target Name="BeforeBuild">
    <Copy Condition=" '$(Configuration)' == 'Debug' " SourceFiles="Pre-Deployment\OnPremises.PreDeploymentScript.sql" DestinationFiles="Pre-Deployment\PreDeploymentScript.sql" OverwriteReadOnlyFiles="true" />
    <Copy Condition=" '$(Configuration)' == 'Release' " SourceFiles="Pre-Deployment\Azure.PreDeploymentScript.sql" DestinationFiles="Pre-Deployment\PreDeploymentScript.sql" OverwriteReadOnlyFiles="true" />
  </Target>
  <Target Name="AfterBuild">
    <Copy SourceFiles="Pre-Deployment\Empty.PreDeploymentScript.sql" DestinationFiles="Pre-Deployment\PreDeploymentScript.sql" OverwriteReadOnlyFiles="true" />
  </Target>

Azure pre-deployment 脚本创建外部数据源(在单独的脚本中,此处未显示)和外部 tables:

IF (NOT EXISTS(SELECT * FROM sys.tables WHERE NAME = 'MyExternalTable' AND is_external = 1))
    BEGIN
        PRINT 'Creating external table: MyExternalTable'

        CREATE EXTERNAL TABLE [MySchema].[MyExternalTable](
            [Id] [int],
            [Name] [nvarchar](3000) NOT NULL
        )
        WITH
        (
            DATA_SOURCE = [ExternalDataSourceName]
        );

        PRINT 'Created external table: MyExternalTable'
    END
ELSE
    BEGIN
        PRINT 'External table ''MyExternalTable'' is already created'
    END
GO

虽然 on-premises 只是创建了一些同义词:

IF NOT EXISTS(SELECT * FROM sys.synonyms WHERE name = 'MyExternalTable')
BEGIN
    CREATE SYNONYM [MySchema].[MyExternalTable] FOR [OtherDb].[OtherSchema].[OtherTable]
END

然后视图可以无缝地使用它,而不必知道它们是使用外部数据源从外部 table 获取数据,还是引用同一服务器上另一个数据库的同义词:

CREATE VIEW [dbo].[MyView] AS SELECT * FROM [Myschema].[MyTable]

虽然感觉有点笨拙,但它似乎工作得很好并且允许使用单个数据库项目部署到 Azure 和 On-Premises(本地)SQL 服务器。