如何引用从同一DACPAC文件部署但具有不同数据库名称的数据库?

时间:2016-02-15 21:47:33

标签: sql-server visual-studio sql-server-data-tools sqlcmd dacpac

背景

我有一个多租户方案和一个独特的Sql Server项目,它将被部署到同一服务器上的多个数据库实例中。每个租户将有一个数据库,加上一个"模型"分贝。

"模型"数据库有三个目的:

  1. 强制某些"系统"数据始终存在于每个租户数据库中
  2. 作为具有编辑系统数据特殊权限的用户的访问点(将准确地同步到所有租户)
  3. 创建新租户时,数据库将被复制并附加一个代表租户的新名称
  4. 有些触发器会检查租户数据库中的已修改/已删除数据是否与" system" "模型中的数据" D b。如果是,则会出现错误,指出系统数据无法更改。

    问题

    因此,这是触发器的一部分,用于检查是否允许删除:

    IF DB_NAME() <> 'ModelTenant' AND EXISTS
        (
        SELECT
            [deleted].*
        FROM
            [deleted]
                INNER JOIN [---MODEL DB NAME??? ---].[MySchema].[MyTable] [ModelTable]
                ON  [deleted].[Guid] = [ModelTable].[Guid]
        )
    BEGIN;
        THROW 50000, 'The DELETE operation on table MyTable cannot be performed. At least one targeted record is reserved by the system and cannot be removed.', 1
    END
    

    我似乎无法找到应该取代的地方--- MODEL DB NAME ??? ---在上面的代码中,允许项目正确编译。在引用完全不同的项目时,我知道该怎么做:使用对SQLCMD变量表示的项目的引用。但在这种情况下,项目参考基本上是同一个项目;仅在不同的数据库上。我似乎无法以这种方式添加自引用。

    我该怎么办? SSDT是否为这种情况提供某种支持?

3 个答案:

答案 0 :(得分:1)

您是否尝试过设置数据库变量?您可以在"Reference aware statements" here下阅读。然后你可以说:

SELECT * FROM [$(MyModelDb)][MySchema].[MyTable] [ModelTable]

如果您没有$(MyModelDb)的特定项目,可以选择“通过未解析的引用来抑制错误......”。自从我使用SSDT项目以来,它一直是永恒的,但我认为这应该有用。

提示:如果需要100次引用1表,您可能会发现创建使用数据库变量的SYNONM更好,然后指向SPROC / TRIGGER中的SYNONM。为什么?因为这样您就不需要部署SPROC / TRIGGER来将变量替换为实际值,这可以使开发更加顺畅。

答案 1 :(得分:1)

我不太确定SSDT是否特别适合任何体面复杂的项目。我可以想到一种或两种最有可能实现这一目标的方法(特别是取决于你如何进行发布/部署),但我认为你实际上会失去的比你获得的更多。我的意思是:你可以添加步骤来实现这一点(即赢得战斗),但你会创建一个更复杂的系统,以便让SSDT发布一个比复杂(和更慢)更复杂的系统它需要(即输掉战争)。

在担心SSDT之前,让我们先看看你为什么需要SSDT来做这件事。您将系统数据与租户数据混合在一起,您需要验证UPDATEDELETE操作以确保系统数据不会被修改,并且是识别数据的唯一方法。系统&#34;数据是通过将其与记录主页 - ModelDB相匹配 - 基于GUID PK。

关于识别哪些数据属于&#34;系统的理论&#34;而不是租户是你的主要问题,而不是SSDT。通过使用&#34;模型&#34;您绝对可以通过多帐篷系统走上正轨。数据库,但使用它进行数据验证是一个糟糕的设计选择:除了使用GUID作为PK已经导致性能下降之外,您还通过漏斗进一步降低了所有这些UPDATEDELETE操作的速度它们通过单点争用,因为所有客户端DBS都需要检查此公共源。

最好在每个表中包含一个BIT字段,用于混合系统和租户数据,表示该行是否是&#34; system&#34;或不。只需查看SQL Server中的系统目录视图:

  • sys.objects有一个is_ms_shipped
  • sys.assemblies走向另一个方向,并有is_user_defined column

因此,如果您要向这些表添加[IsSystemData] BIT NOT NULL列,您的触发器逻辑将变为:

IF DB_NAME() <> N'ModelTenant' AND EXISTS
    (
    SELECT del.*
    FROM   [deleted] del
    WHERE  del.[IsSystemData] = 1
    )
BEGIN
    ;THROW 50000, 'The DELETE operation on table MyTable cannot be performed. At least one targeted record is reserved by the system and cannot be removed.', 1;
END;

优点:

  • 不再有SSDT问题(至少从这部分开始; - )
  • 更快UPDATEDELETE次操作
  • 减少对共享资源的争用(即ModelDB
  • 代码复杂度降低

答案 2 :(得分:1)

作为引用另一个数据库项目的替代方法,您可以生成一个dacpac,然后将dacpac作为数据库引用引用到相同的服务器,不同的数据库&#34;模式。