Another error in transactional replication is the one related to Identity columns. That error is easy to fix and it is being raised if the setting “not for replication” is set to incorrect value on SUBSCRIBER database.
Lets start from beginning with creating table that includes identity column with following script (we do not specify “Not for Replication”, by default it will be set to 0):
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Table_IdentityA]( [RowID] [bigint] IDENTITY(1,1) NOT NULL, [Field1_int] [int] NOT NULL, [Field2_int] [int] NOT NULL CONSTRAINT [PK_IdentityA] PRIMARY KEY CLUSTERED ( [RowID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY] ) ON [PRIMARY] GO
After adding that table into Publication with following setting:
@identityrangemanagementoption = N’none’
Here is the script:
use [PublishedDB] exec sp_addarticle @publication = N'IDENTITY_Test', @article = N'Table_IdentityA', @source_owner = N'dbo', @source_object = N'Table_IdentityA', @type = N'logbased', @description = N'', @creation_script = N'', @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'none', @destination_table = N'Table_IdentityA', @destination_owner = N'dbo', @status = 24, @vertical_partition = N'false', @ins_cmd = N'CALL [sp_MSins_dboTable_IdentityA]', @del_cmd = N'CALL [sp_MSdel_dboTable_IdentityA]', @upd_cmd = N'SCALL [sp_MSupd_dboTable_IdentityA]' GO
As there is identity column in that table SQL won’t allow you specifying ‘none’. You will get following error.
“Msg 21830, Level 16, State 1, Procedure sp_MSrepl_addarticle, Line 2124
You cannot specify schema_option 0x4 (script identity as identity rather than the base data type) for article ‘Table_IdentityA’. The value specified for the parameter @identityrangemanagementoption is NONE. To replicate identity as identity, the value must be MANUAL or AUTO for publications that do not support queued updating subscriptions.”
AUTO setting is only allowed when using updating subscriptions:
Automatic identity range support is useful only for publications that allow updating subscribers.
Microsoft is suggesting to avoid that setting:
The only setting that we left is MANUAL. Lets add article with that setting set to Manual.
use [PublishedDB] exec sp_addarticle @publication = N'IDENTITY_Test', @article = N'Table_IdentityA', @source_owner = N'dbo', @source_object = N'Table_IdentityA', @type = N'logbased', @description = N'', @creation_script = N'', @pre_creation_cmd = N'drop', @schema_option = 0x000000000803509F, @identityrangemanagementoption = N'manual', @destination_table = N'Table_IdentityA', @destination_owner = N'dbo', @status = 24, @vertical_partition = N'false', @ins_cmd = N'CALL [sp_MSins_dboTable_IdentityA]', @del_cmd = N'CALL [sp_MSdel_dboTable_IdentityA]', @upd_cmd = N'SCALL [sp_MSupd_dboTable_IdentityA]' GO
This time no error. After Initializing and sending snapshot down to Subscriber,lets check what we have in Not For Replication.
A bit surprise it is different than on Publisher. now lets try to insert rows into that table on Publisher. No issues there all 10 rows inserted properly:
Lets see what has changed on Publisher:
As you can see setting “Not for Replication” has changed to 1. I did test it and it seems while adding a table with identity column into Publication, either with GUI or T-SQL that setting is being changed to 1. Replication taking care of it from it side and I would not touch that setting on Subscriber. Pretty much which ever setting it is set on Publisher it will be always changed when adding table to Publication (changed to 1).
You can also see that replication procedure for that table is passing the value of Identity column (RowId):
CREATE procedure [dbo].[sp_MSins_dboTable_IdentityA] @c1 bigint, @c2 int, @c3 int as begin insert into [dbo].[Table_IdentityA]( [RowID], [Field1_int], [Field2_int] ) values ( @c1, @c2, @c3 ) end
The error I mentioned at the begging can be caused only in two scenarios. First someone manually changed that setting on Subscriber database. Second is that tables on subscriber were created manually instead of snapshot. In the second scenario for example we used a backup of Published database (before Publication has been created) and restore it on Subscriber to initialize from backup.
Solution
In order to fix that error you can run following script on Subscriber database and provide table name that have an issue:
DECLARE @ApplicableObjectID INT SET @ApplicableObjectID = OBJECT_ID('
‘
) EXEC sp_identitycolumnforreplication @ApplicableObjectID,1
That script will change ‘Not For Replication’ to 1 and fix the error that you have with your distribution agent.
Alternatively to prevent that happen for other table you can change that setting to all tables on Subscriber (that are populated by replication) using script
select 'EXEC sp_identitycolumnforreplication ' + CAST(c.id AS VARCHAR(10)) + ', 1' ,t.name FROM syscolumns c join sys.tables t on c.id=t.object_id WHERE columnproperty(c.id, c.name, 'IsIdentity') = 1 AND columnproperty(c.id, c.name, 'IsIdNotForRepl') = 0 AND is_ms_shipped <>1
That script will do all user tables that has Identity column and set “Not For Replication” = 0 and set it to 1.
Lastly I would not recommend modifying replication procedures on Subscriber by adding SET IDENTITY_INSERT setting. As any changes to table schema will update that proc to old version and it will break distribution agent again.
Even if that error is not so common I hope it helped you better understand how identity is managed by transactional replication.