We have a merge replication set up on Sql Server 2008 R2. There are many tables with foreign keys providing a logical dependence on each other. For this question, let's say there are the "User" and "File" tables, where "File" has a foreign key for the user who created the file.
We often see conflicts of the "constraint violation" type when a User and File have been created on a subscriber, on exactly this FK, implying that a row insert was attempted on the File table with a user_id that doesn't exist in User.
However, once synchronisation is finished, the new User does exist on the publisher. The new File doesn't, and has the conflict mentioned above. This seems to imply that while both tables were synchronised by replication, they were done in the wrong order.
Using SSMS, I can see that the FK in question (and all others) has the "Enforce for replication" option set to "Yes" on the publisher, but set to "No" on the subscriber.
I was not the one who created the tables (and that person doesn't work here any longer) so I can't know for sure if the FKs were created with "NOT FOR REPLICATION". However if I try to Script Table as > CREATE to > New Query Editor Window, no such flag is present on either Publisher or Subscriber:
ALTER TABLE [dbo].[File] WITH CHECK ADD CONSTRAINT [FK_File_User] FOREIGN KEY([user_id])
REFERENCES [dbo].[User] ([user_id])
GO
ALTER TABLE [dbo].[File] CHECK CONSTRAINT [FK_File_User]
GO
Am I correct in assuming that the conflicts are caused by the "Enforce for replication" setting being "No" on all subscribers? And if that is the case, how do we ensure they are set to yes when creating new subscribers?
The subscriber database is created manually as an empty database before the first synchronisation and populated (both schema and data) by replication itself.
In case it matters, these are the (censored) scripts used when a new subscriber is added.
On the publisher:
declare @db_name nvarchar(50) = N'SubscriberDB';
declare @client nvarchar(50) = N'Subscriber\SQLEXPRESS';
use [PublisherDB]
exec sp_addmergesubscription @publication = N'sync', @subscriber = @client, @subscriber_db = @db_name, @subscription_type = N'pull', @subscriber_type = N'global', @subscription_priority = 75, @sync_type = N'Automatic'
On the subscriber:
declare @db_name nvarchar(50) = N'PublisherDB';
declare @net_timeout int = 900;
use [SubscriberDB]
exec sp_addmergepullsubscription @publisher = N'Server', @publication = N'sync', @publisher_db = @db_name, @subscriber_type = N'Global', @subscription_priority = 75, @description = N'', @sync_type = N'Automatic'
exec sp_addmergepullsubscription_agent @publisher = N'Server', @publisher_db = @db_name, @publication = N'sync', @distributor = N'Server', @distributor_security_mode = 0, @distributor_login = N'dlogin', @distributor_password = N'dpassword', @enabled_for_syncmgr = N'True', @frequency_type = 4, @frequency_interval = 1, @frequency_relative_interval = 1, @frequency_recurrence_factor = 0, @frequency_subday = 8, @frequency_subday_interval = 1, @active_start_time_of_day = 0, @active_end_time_of_day = 235959, @active_start_date = 0, @active_end_date = 0, @alt_snapshot_folder = N'', @working_directory = N'', @use_ftp = N'False', @job_login = null, @job_password = null, @publisher_security_mode = 0, @publisher_login = N'plogin', @publisher_password = N'ppassword', @use_interactive_resolver = N'False', @dynamic_snapshot_location = N'', @use_web_sync = 1, @internet_url = N'https://ourserver/replisapi.dll', @internet_login = N'ilogin', @internet_password = 'ipassword', @internet_security_mode = 0, @internet_timeout = @net_timeout
GO