我们的SSDT数据库项目包括一个具有计算列的表,该列可以根据客户要求采用多种形式之一。我正在试图弄清楚如何管理这个计算列,这样我们仍然可以使用Publish功能,而不会将每个人的列恢复为默认值。
我想要完成的内容可以在以下 无效 T-SQL代码中解释:
CREATE TABLE dbo.Customer
(
Id INTEGER,
Region INTEGER,
Name VARCHAR(50),
AccountNumber AS dbo.FormatAccountNumber(Id, Region)
)
CREATE FUNCTION [dbo].[FormatAccountNumber]
(
@Id INTEGER,
@Region INTEGER
)
RETURNS VARCHAR(20)
AS
BEGIN
IF '$(AccountType)' = 'Regional'
RETURN CONVERT(VARCHAR, @Region) + '-' + CONVERT(VARCHAR, @Id)
IF '$(AccountType)' = 'Merged'
RETURN CONVERT(VARCHAR, @Region * 100000 + @Id)
IF '$(AccountType)' = 'Flat'
RETURN CONVERT(VARCHAR, @Id)
END
当然,这不起作用,因为$(AccountType)
SQLCMD变量不能在函数内部使用,并且无论如何都不会在运行时正确设置。我也尝试将SQLCMD条件化为整个函数:
IF '$(AccountType)' = 'Flat'
CREATE FUNCTION ...
但是这会产生错误“CREATE FUNCTION必须是批处理中的唯一语句。”
有没有办法在SSDT项目中进行任何类型的模式条件编译?如果没有,我在SSDT发布过程中有哪些选项来维护这种可自定义的字段?
答案 0 :(得分:2)
您可以使用Post-Deploment脚本在动态SQL中强制部署对象:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[FormatAccountNumber]')
AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
EXEC('CREATE FUNCTION [dbo].[FormatAccountNumber] () RETURNS BIT AS BEGIN RETURN 0 END')
GO
IF '$(AccountType)' = 'Regional'
BEGIN
EXEC('
ALTER FUNCTION [dbo].[FormatAccountNumber]
(
@Id INTEGER,
@Region INTEGER
)
RETURNS VARCHAR(20)
AS
BEGIN
RETURN CONVERT(VARCHAR, @Region) + ''-'' + CONVERT(VARCHAR, @Id)
END
')
END
请注意,通过执行此操作,您将无法对SSDT数据库项目中的dbo.FormatAccountNumber
函数进行任何引用(除非这些对象也包含在部署后脚本中)。
我还玩了一个替代解决方案,其中涉及.sqlproj
文件本身内的附加条件(在ItemGroup
元素内),但由于MsBuild Properties不完全像 - 所以这确实有点混乱与SQLCMD变量类似,但如果你愿意,我可以发布这个。
如果您发现自己需要经常在数据库中有条件地部署对象,您可能会考虑转向基于命令式的部署解决方案(而不是SSDT项目的声明式)。命令式部署(通常称为迁移)使您可以更好地控制部署时行为。
免责声明:我是ReadyRoll的创始人,ReadyRoll为使用命令式部署的VS制作产品。
答案 1 :(得分:0)
我在MSDN上就此需求进行了公开讨论。没有取得多大进展。理想情况允许您在基本ssdt项目中将db对象标记为“可继承”,以便引用基础项目或DAC的其他项目不会抱怨重复对象,并且只会创建基础对象或“存根”它不存在。这将允许您拥有数据库模型的“层”。请参阅msdn Extending SSDT Composite Solutions with Overriden Stored Procedures
上的帖子