Partager via


Définir une relation d’enregistrement logique entre des articles de table de fusion

S'applique à : SQL Server

Cette rubrique explique comment définir une relation d'enregistrement logique entre des articles de table de fusion dans SQL Server à l'aide de SQL Server Management Studio, Transact-SQL ou de RMO (Replication Management Objects).

La réplication de fusion vous permet de définir une relation entre des lignes connexes dans des tables distinctes. Ces lignes peuvent alors être traitées comme une unité transactionnelle au cours de la synchronisation. Un enregistrement logique peut être défini entre deux articles qu'ils aient ou non une relation de filtre de jointure. Pour plus d’informations, consultez Regrouper les modifications apportées à des lignes connexes à l’aide d’enregistrements logiques.

Remarque

Cette fonctionnalité sera supprimée dans une version future de SQL Server. Évitez d'utiliser cette fonctionnalité dans de nouveaux travaux de développement, et prévoyez de modifier les applications qui utilisent actuellement cette fonctionnalité.

Dans cette rubrique

Avant de commencer

Limitations et restrictions

  • Si vous ajoutez, modifiez ou supprimez un enregistrement logique après que les abonnements à la publication aient été initialisés, vous devez générer un nouvel instantané et réinitialiser tous les abonnements après avoir effectué la modification. Pour plus d’informations sur les exigences relatives aux changements de propriétés, consultez Changer les propriétés des publications et des articles.

Utilisation de SQL Server Management Studio

Définissez des enregistrements logiques dans la boîte de dialogue Ajouter une jointure, disponible dans l'Assistant Nouvelle publication, ainsi que dans la boîte de dialogue Propriétés de la publication – <Publication>. Pour plus d’informations sur l’utilisation de l’Assistant et sur l’accès à la boîte de dialogue, consultez Créer une publication et Afficher et modifier les propriétés d’une publication.

Les enregistrements logiques peuvent être définis dans la boîte de dialogue Ajouter une jointure seulement s'ils sont appliqués à un filtre de jointure dans une publication de fusion, et si la publication satisfait aux conditions requises pour l'utilisation de partitions précalculées. Pour définir des enregistrements logiques qui ne sont pas appliqués à des filtres de jointure et pour définir la détection et la résolution des conflits au niveau des enregistrements logiques, vous devez utiliser des procédures stockées.

Pour définir une relation d'enregistrement logique

  1. Dans la page Filtrer les lignes de la table de l'Assistant Nouvelle publication ou la page Filtrer les lignes de la boîte de dialogue Propriétés de la publication – <Publication>, sélectionnez un filtre de lignes dans le volet Tables filtrées.

    Une relation d'enregistrement logique est associée à un filtre de jointure, qui étend un filtre de lignes. Vous devez donc définir un filtre de lignes avant de pouvoir étendre le filtre avec une jointure et appliquer une relation d'enregistrement logique. Après avoir défini un filtre de jointure, vous pouvez l'étendre avec un autre filtre de jointure. Pour plus d'informations sur la définition de filtres de jointure, consultez Définir et modifier un filtre de jointure entre des articles de fusion.

  2. Cliquez sur Ajouter, puis sur Ajouter une jointure pour étendre le filtre sélectionné.

  3. Définissez un filtre de jointure dans la boîte de dialogue Ajouter une jointure , puis activez la case à cocher Enregistrement logique.

  4. Si vous êtes dans la boîte de dialogue Propriétés de la publication – <Publication>, cliquez sur OK pour enregistrer et fermer la boîte de dialogue.

Pour supprimer une relation d'enregistrement logique

  • Supprimer seulement la relation d'enregistrement logique ou supprimer la relation d'enregistrement logique et le filtre de jointure qui y est associé.

    Pour supprimer seulement la relation d'enregistrement logique :

    1. Dans la page Filtrer les lignes de l'Assistant Nouvelle publication ou dans la page Filtrer les lignes de la boîte de dialogue Propriétés de la publication – <Publication>, sélectionnez le filtre de jointure associé à la relation d'enregistrements logiques dans le volet Tables filtrées, puis cliquez sur Modifier.

    2. Dans la boîte de dialogue Modifier une jointure , désactivez la case à cocher Enregistrement logique.

    3. Cliquez sur OK.

    Pour supprimer la relation d'enregistrement logique et le filtre de jointure qui y est associé :

    • Dans la page Filtrer les lignes de l'Assistant Nouvelle publication ou dans la boîte de dialogue Propriétés de la publication – <Publication>, sélectionnez un filtre dans le volet Tables filtrées, puis cliquez sur Supprimer. Si le filtre de jointure que vous supprimez est lui-même étendu par d'autres jointures, ces jointures seront aussi supprimées.

Utilisation de Transact-SQL

Vous pouvez spécifier par programme des relations d'enregistrements logiques entre des articles en utilisant des procédures stockées de réplication.

Pour définir une relation d'enregistrement logique sans filtre de jointure associé

  1. Si la publication contient des articles filtrés, exécutez sp_helpmergepublicationet notez la valeur de use_partition_groups dans le jeu de résultats.

    • Si la valeur est 1, les partitions précalculées sont déjà utilisées.

    • Si la valeur est 0, exécutez sp_changemergepublication au niveau du serveur de publication dans la base de données de publication. Affectez la valeur use_partition_groups à @property et la valeur true à @value.

      Remarque

      Si la publication ne prend pas en charge les partitions précalculées, les enregistrements logiques ne peuvent pas être utilisés. Pour plus d’informations, consultez « Conditions requises à l’utilisation des partitions précalculées » dans la rubrique Optimiser les performances des filtres paramétrés avec des partitions précalculées.

    • Si la valeur est NULL, l'Agent d'instantané doit être exécuté pour générer l'instantané initial de la publication.

  2. Si les articles qui constitueront l'enregistrement logique n'existent pas, exécutez sp_addmergearticle au niveau du serveur de publication dans la base de données de publication. Spécifiez l'une des options de détection et de résolution des conflits suivantes pour l'enregistrement logique :

    • Pour détecter et résoudre les conflits qui se produisent dans des lignes connexes de l'enregistrement logique, affectez la valeur true à @logical_record_level_conflict_detection et @logical_record_level_conflict_resolution.

    • Pour utiliser la détection et la résolution standard des conflits au niveau des lignes ou des colonnes, affectez la valeur false à @logical_record_level_conflict_detection et @logical_record_level_conflict_resolution, qui est la valeur par défaut.

  3. Répétez l'étape 2 pour chaque article qui constituera l'enregistrement logique. Vous devez utiliser la même option de détection et de résolution des conflits pour chaque article de l'enregistrement logique. Pour plus d'informations, voir Détection et résolution des conflits dans les enregistrements logiques.

  4. Dans la base de données de publication sur le serveur de publication, exécutez sp_addmergefilter. Spécifiez @publication, le nom d'un article de la relation pour @article, le nom du deuxième article pour @join_articlename, le nom de la relation pour @filtername, une clause qui définit la relation entre les deux articles pour @join_filterclause, le type de jointure pour @join_unique_key et affectez l'une des valeurs suivantes à @filter_type:

    • 2 - définit une relation logique.

    • 3 - définit une relation logique avec un filtre de jointure.

    Remarque

    Si aucun filtre de jointure n'est pas utilisé, la direction de la relation entre les deux articles n'est pas importante.

  5. Répétez l'étape 2 pour chaque relation d'enregistrement logique restante dans la publication.

Pour modifier la détection et la résolution des conflits pour les enregistrements logiques

  1. Pour détecter et résoudre les conflits qui se produisent dans des lignes connexes de l'enregistrement logique :

    • Dans la base de données de publication sur le serveur de publication, exécutez sp_changemergearticle. Affectez la valeur logical_record_level_conflict_detection à @property et la valeur true à @value. Affectez la valeur 1 à @force_invalidate_snapshot et @force_reinit_subscription.

    • Dans la base de données de publication sur le serveur de publication, exécutez sp_changemergearticle. Affectez la valeur logical_record_level_conflict_resolution à @property et la valeur true à @value. Affectez la valeur 1 à @force_invalidate_snapshot et @force_reinit_subscription.

  2. Pour utiliser la détection et la résolution standard des conflits au niveau des lignes ou des colonnes :

    • Dans la base de données de publication sur le serveur de publication, exécutez sp_changemergearticle. Affectez la valeur logical_record_level_conflict_detection à @property et la valeur false à @value. Affectez la valeur 1 à @force_invalidate_snapshot et @force_reinit_subscription.

    • Dans la base de données de publication sur le serveur de publication, exécutez sp_changemergearticle. Affectez la valeur logical_record_level_conflict_resolution à @property et la valeur false à @value. Affectez la valeur 1 à @force_invalidate_snapshot et @force_reinit_subscription.

Pour supprimer une relation d'enregistrements logiques

  1. Dans la base de données de publication sur le serveur de publication, exécutez la requête suivante afin que des informations sur toutes les relations d'enregistrements logiques définies pour la publication spécifiée soient retournées :

    SELECT f.* FROM sysmergesubsetfilters AS f 
    INNER JOIN sysmergepublications AS p
    ON f.pubid = p.pubid WHERE p.[name] = @publication;
    

    Notez le nom de la relation d'enregistrements logiques en cours de suppression dans la colonne filtername du jeu de résultats.

    Remarque

    Cette requête retourne les mêmes informations que sp_helpmergefilterToutefois, cette procédure stockée système retourne seulement des informations sur les relations d'enregistrements logiques qui sont également des filtres de jointure.

  2. Dans la base de données de publication sur le serveur de publication, exécutez sp_dropmergefilter. Spécifiez @publication, le nom de l'un des articles de la relation pour @articleet le nom de la relation de l'étape 1 pour @filtername.

Exemple (Transact-SQL)

Cet exemple active les partitions précalculées sur une publication existante et crée un enregistrement logique qui comprend les deux nouveaux articles des tables SalesOrderHeader et SalesOrderDetail .

-- Remove ON DELETE CASCADE from FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID;
-- logical records cannot be used with ON DELETE CASCADE. 
IF EXISTS (SELECT * FROM sys.objects 
WHERE name = 'FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID')
BEGIN
    ALTER TABLE [Sales].[SalesOrderDetail] 
    DROP CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
END

ALTER TABLE [Sales].[SalesOrderDetail]  
WITH CHECK ADD CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
FOREIGN KEY([SalesOrderID])
REFERENCES [Sales].[SalesOrderHeader] ([SalesOrderID])
GO

DECLARE @publication    AS sysname;
DECLARE @table1 AS sysname;
DECLARE @table2 AS sysname;
DECLARE @table3 AS sysname;
DECLARE @salesschema AS sysname;
DECLARE @hrschema AS sysname;
DECLARE @filterclause AS nvarchar(1000);
DECLARE @partitionoption AS bit;
SET @publication = N'AdvWorksSalesOrdersMerge'; 
SET @table1 = N'SalesOrderDetail'; 
SET @table2 = N'SalesOrderHeader'; 
SET @salesschema = N'Sales';
SET @hrschema = N'HumanResources';
SET @filterclause = N'Employee.LoginID = HOST_NAME()';

-- Ensure that the publication uses precomputed partitions.
SET @partitionoption = (SELECT [use_partition_groups] FROM sysmergepublications 
    WHERE [name] = @publication);
IF @partitionoption <> 1
BEGIN
    EXEC sp_changemergepublication 
        @publication = @publication, 
        @property = N'use_partition_groups', 
        @value = 'true',
        @force_invalidate_snapshot = 1;
END  

-- Add a filtered article for the Employee table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table1, 
  @source_object = @table1, 
  @type = N'table', 
  @source_owner = @hrschema,
  @schema_option = 0x0004CF1,
  @description = N'article for the Employee table',
  @subset_filterclause = @filterclause;

-- Add an article for the SalesOrderHeader table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table2, 
  @source_object = @table2, 
  @type = N'table', 
  @source_owner = @salesschema,
  @schema_option = 0x0034EF1,
  @description = N'article for the SalesOrderHeader table';

-- Add an article for the SalesOrderDetail table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table3, 
  @source_object = @table3, 
  @source_owner = @salesschema,
  @description = 'article for the SalesOrderDetail table', 
  @identityrangemanagementoption = N'auto', 
  @pub_identity_range = 100000, 
  @identity_range = 100, 
  @threshold = 80;

-- Add a merge join filter between Employee and SalesOrderHeader.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table2, 
  @filtername = N'SalesOrderHeader_Employee', 
  @join_articlename = @table1, 
  @join_filterclause = N'Employee.EmployeeID = SalesOrderHeader.SalesPersonID', 
  @join_unique_key = 1, 
  @filter_type = 1, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;

-- Create a logical record relationship that is also a merge join 
-- filter between SalesOrderHeader and SalesOrderDetail.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table3, 
  @filtername = N'LogicalRecord_SalesOrderHeader_SalesOrderDetail', 
  @join_articlename = @table2, 
  @join_filterclause = N'[SalesOrderHeader].[SalesOrderID] = [SalesOrderDetail].[SalesOrderID]', 
  @join_unique_key = 1, 
  @filter_type = 3, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;
GO

Utilisation d'objets RMO (Replication Management Objects)

Remarque

La réplication de fusion vous permet de spécifier que les conflits soient suivis et résolus au niveau des enregistrements logiques, mais ces options ne peuvent pas être définies à l'aide des objets RMO.

Pour définir une relation d'enregistrement logique sans filtre de jointure associé

  1. Créez une connexion au serveur de publication en utilisant la classe ServerConnection .

  2. Créez une instance de la classe MergePublication , définissez les propriétés Name et DatabaseName pour la publication et définissez la propriété ConnectionContext sur la connexion créée à l'étape 1.

  3. Appelez la méthode LoadProperties pour obtenir les propriétés de l'objet. Si cette méthode retourne false, soit les propriétés de la publication ont été définies de manière incorrecte à l'étape 2, soit la publication n'existe pas.

  4. Si la propriété PartitionGroupsOption a la valeur False, affectez-lui la valeur True.

  5. Si les articles devant inclure l'enregistrement logique n'existent pas, créez une instance de la classe MergeArticle et définissez les propriétés suivantes :

    • Le nom de l'article pour Name.

    • Le nom de la publication pour PublicationName.

    • (Facultatif) Si l'article est filtré horizontalement, spécifiez la clause de filtre de lignes pour la propriété FilterClause . Utilisez cette propriété pour spécifier un filtre de lignes statique ou paramétrable. Pour plus d'informations, voir Parameterized Row Filters.

    Pour plus d’informations, consultez définir un Article.

  6. Appelez la méthode Create .

  7. Répétez les étapes 5 et 6 pour chaque article qui comprend l'enregistrement logique.

  8. Créez une instance de la classe MergeJoinFilter pour définir la relation d'enregistrement logique entre les articles. Définissez ensuite les propriétés suivantes :

  9. Appelez la méthode AddMergeJoinFilter sur l'objet qui représente l'article enfant dans la relation. Passez l'objet MergeJoinFilter créé à l'étape 8 pour définir la relation.

  10. Répétez les étapes 8 et 9 pour chaque relation d'enregistrement logique restante dans la publication.

Exemple (RMO)

Cet exemple crée un enregistrement logique qui comprend les deux nouveaux articles pour les tables SalesOrderHeader et SalesOrderDetail .

           // Define the Publisher and publication names.
           string publisherName = publisherInstance;
           string publicationName = "AdvWorksSalesOrdersMerge";
           string publicationDbName = "AdventureWorks2022";

           // Specify article names.
           string articleName1 = "SalesOrderHeader";
           string articleName2 = "SalesOrderDetail";
           
           // Specify logical record information.
           string lrName = "SalesOrderHeader_SalesOrderDetail";
           string lrClause = "[SalesOrderHeader].[SalesOrderID] = "
               + "[SalesOrderDetail].[SalesOrderID]";

           string schema = "Sales";

           MergeArticle article1 = new MergeArticle();
           MergeArticle article2 = new MergeArticle();
           MergeJoinFilter lr = new MergeJoinFilter();
           MergePublication publication = new MergePublication();

           // Create a connection to the Publisher.
           ServerConnection conn = new ServerConnection(publisherName);

           try
           {
               // Connect to the Publisher.
               conn.Connect();

               // Verify that the publication uses precomputed partitions.
               publication.Name = publicationName;
               publication.DatabaseName = publicationDbName;
               publication.ConnectionContext = conn;

               // If we can't get the properties for this merge publication, then throw an application exception.
               if (publication.LoadProperties())
               {
                   // If precomputed partitions is disabled, enable it.
                   if (publication.PartitionGroupsOption == PartitionGroupsOption.False)
                   {
                       publication.PartitionGroupsOption = PartitionGroupsOption.True;
                   }
               }
               else
               {
                   throw new ApplicationException(String.Format(
                       "Settings could not be retrieved for the publication. " +
                       "Ensure that the publication {0} exists on {1}.",
                       publicationName, publisherName));
               }

               // Set the required properties for the PurchaseOrderHeader article.
               article1.ConnectionContext = conn;
               article1.Name = articleName1;
               article1.DatabaseName = publicationDbName;
               article1.SourceObjectName = articleName1;
               article1.SourceObjectOwner = schema;
               article1.PublicationName = publicationName;
               article1.Type = ArticleOptions.TableBased;

               // Set the required properties for the SalesOrderDetail article.
               article2.ConnectionContext = conn;
               article2.Name = articleName2;
               article2.DatabaseName = publicationDbName;
               article2.SourceObjectName = articleName2;
               article2.SourceObjectOwner = schema;
               article2.PublicationName = publicationName;
               article2.Type = ArticleOptions.TableBased;

               if (!article1.IsExistingObject) article1.Create();
               if (!article2.IsExistingObject) article2.Create();

               // Define a logical record relationship between 
               // PurchaseOrderHeader and PurchaseOrderDetail. 

               // Parent article.
               lr.JoinArticleName = articleName1;
               
               // Child article.
               lr.ArticleName = articleName2;
               lr.FilterName = lrName;
               lr.JoinUniqueKey = true;
               lr.FilterTypes = FilterTypes.LogicalRecordLink;
               lr.JoinFilterClause = lrClause;

               // Add the logical record definition to the parent article.
               article1.AddMergeJoinFilter(lr);
           }
           catch (Exception ex)
           {
               // Do error handling here and rollback the transaction.
               throw new ApplicationException(
                   "The filtered articles could not be created", ex);
           }
           finally
           {
               conn.Disconnect();
           }
' Define the Publisher and publication names.
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2022"

' Specify article names.
Dim articleName1 As String = "SalesOrderHeader"
Dim articleName2 As String = "SalesOrderDetail"

' Specify logical record information.
Dim lrName As String = "SalesOrderHeader_SalesOrderDetail"
Dim lrClause As String = "[SalesOrderHeader].[SalesOrderID] = " _
        & "[SalesOrderDetail].[SalesOrderID]"

Dim schema As String = "Sales"

Dim article1 As MergeArticle = New MergeArticle()
Dim article2 As MergeArticle = New MergeArticle()
Dim lr As MergeJoinFilter = New MergeJoinFilter()
Dim publication As MergePublication = New MergePublication()

' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)

Try
    ' Connect to the Publisher.
    conn.Connect()

    ' Verify that the publication uses precomputed partitions.
    publication.Name = publicationName
    publication.DatabaseName = publicationDbName
    publication.ConnectionContext = conn

    ' If we can't get the properties for this merge publication, then throw an application exception.
    If publication.LoadProperties() Then
        ' If precomputed partitions is disabled, enable it.
        If publication.PartitionGroupsOption = PartitionGroupsOption.False Then
            publication.PartitionGroupsOption = PartitionGroupsOption.True
        End If
    Else
        Throw New ApplicationException(String.Format( _
            "Settings could not be retrieved for the publication. " _
            & "Ensure that the publication {0} exists on {1}.", _
            publicationName, publisherName))
    End If

    ' Set the required properties for the SalesOrderHeader article.
    article1.ConnectionContext = conn
    article1.Name = articleName1
    article1.DatabaseName = publicationDbName
    article1.SourceObjectName = articleName1
    article1.SourceObjectOwner = schema
    article1.PublicationName = publicationName
    article1.Type = ArticleOptions.TableBased

    ' Set the required properties for the SalesOrderDetail article.
    article2.ConnectionContext = conn
    article2.Name = articleName2
    article2.DatabaseName = publicationDbName
    article2.SourceObjectName = articleName2
    article2.SourceObjectOwner = schema
    article2.PublicationName = publicationName
    article2.Type = ArticleOptions.TableBased

    If Not article1.IsExistingObject Then
        article1.Create()
    End If
    If Not article2.IsExistingObject Then
        article2.Create()
    End If

    ' Define a logical record relationship between 
    ' SalesOrderHeader and SalesOrderDetail. 

    ' Parent article.
    lr.JoinArticleName = articleName1
    ' Child article.
    lr.ArticleName = articleName2
    lr.FilterName = lrName
    lr.JoinUniqueKey = True
    lr.FilterTypes = FilterTypes.LogicalRecordLink
    lr.JoinFilterClause = lrClause

    ' Add the logical record definition to the parent article.
    article1.AddMergeJoinFilter(lr)
Catch ex As Exception
    ' Do error handling here and rollback the transaction.
    Throw New ApplicationException( _
            "The filtered articles could not be created", ex)
Finally
    conn.Disconnect()
End Try