VSTS for DB Pro Schema Update con Merge Replication
Una delle numerose e interessanti feature di VSTS for DB Pro consente di modificare gli oggetti database direttamente nel progetto per poi generare lo script di update che può essere applicato al DB reale o di test.
Inoltre VSTS for DB Pro consente di effettuare Refactoring consistente su oggetti DB. Ad esempio si può rinominare un campo di una tabella ottenendo in automatico il rename del campo in tutti gli oggetti db che in qualche modo hanno a che fare con il campo stesso (stored procedure, function, trigger, indici, relazioni etc).
Esiste però un problema (a cui sto cercando un workaround semplice e indolore..vi farò sapere) nello script generato per effettuare la modifica. Ad esempio: rinominando un campo si ottiene il seguente script (ho preso una tabella di un mio famoso DB di Demo).
Ho rinominato il campo Nome in CampeggioNome.
BEGIN TRANSACTION
GO
PRINT
N
'Dropping constraints from [dbo].[Campeggi]'
GO
ALTER TABLE
[dbo].[Campeggi]
DROP CONSTRAINT [PK_Campeggi]
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
PRINT
N
'Dropping constraints from [dbo].[Campeggi]'
GO
ALTER TABLE
[dbo].[Campeggi]
DROP CONSTRAINT [MSmerge_df_rowguid_F7AE60381A2441C8BA14010D6380F219]
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
DROP INDEX
[MSmerge_index_661577395]
ON [dbo].[Campeggi]
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
PRINT
N
'Rebuilding [dbo].[Campeggi]'
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SET
XACT_ABORT
ON
GO
BEGIN TRANSACTION
CREATE TABLE
[dbo].[tmp_ms_xx_Campeggi]
(
[IdCampeggio] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[CampeggioNome] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[rowguid] [uniqueidentifier] NOT NULL ROWGUIDCOL CONSTRAINT [MSmerge_df_rowguid_F7AE60381A2441C8BA14010D6380F219] DEFAULT (newsequentialid())
) ON [PRIMARY]
INSERT INTO
[dbo].[tmp_ms_xx_Campeggi]([IdCampeggio], [rowguid])
SELECT [IdCampeggio], [rowguid]
FROM [dbo].[Campeggi]
DROP TABLE
[dbo].[Campeggi]
EXEC
sp_rename N
'[dbo].[tmp_ms_xx_Campeggi]', N
'Campeggi'
COMMIT TRANSACTION
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
PRINT
N
'Creating primary key [PK_Campeggi] on [dbo].[Campeggi]'
GO
ALTER TABLE
[dbo].[Campeggi]
ADD CONSTRAINT [PK_Campeggi]
PRIMARY KEY CLUSTERED ([IdCampeggio])
ON [PRIMARY]
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
PRINT
N
'Creating index [MSmerge_index_661577395] on [dbo].[Campeggi]'
GO
CREATE UNIQUE NONCLUSTERED INDEX
[MSmerge_index_661577395]
ON [dbo].[Campeggi] ([rowguid])
ON [PRIMARY]
GO
IF
@@ERROR<>0
AND @@TRANCOUNT>0
ROLLBACK TRANSACTION
GO
IF
@@TRANCOUNT=0
BEGIN INSERT INTO #tmpErrors (Error)
SELECT 1
BEGIN TRANSACTION END
GO
Come si nota vengono dapprima rimossi indici, constraint e trigger per poi
1) Creare una tabella temporanea con la nuova struttura
2) Importare i dati dalla tabella originale nella tabella temporanea
3) Eseguire un DROP della tabella originale
4) Rinominare la tabella temporanea con il nome originale
Questa operazione, è impossibile da eseguire se la tabella è stata oggetto di una pubblicazione. Quando una tabella è stata inserita in una Publication di una replica di tipo merge non può essere rimossa dal DB se non dopo aver tolto il riferimento nella pubblicazione.
Quindi l'aggiornamento automatico da DB Professional non può essere effettuato e occorre modificare lo script generato per tutte le tabelle sotto Merge Replication. In pratica lo stesso risultato che si ottiene da Management Studio o dall'Enterprise Manager.