Zdefiniuj logiczne powiązanie rekordów między artykułami tabeli scalania

Dotyczy:SQL Server

Ten temat opisuje, jak zdefiniować logiczne powiązania rekordów między artykułami tabeli scalania w SQL Server, korzystając z SQL Server Management Studio, Transact-SQL lub Replication Management Objects (RMO).

Replikacja scalania pozwala zdefiniować relację między powiązanymi wierszami w różnych tabelach. Te wiersze mogą być następnie przetwarzane jako jednostka transakcyjna podczas synchronizacji. Logiczny rekord można zdefiniować pomiędzy dwoma artykułami, niezależnie od tego, czy mają one relację filtra łączenia, czy nie. Aby uzyskać więcej informacji, zobacz Grupowanie zmian w powiązanych wierszach z rekordami logicznymi.

Uwaga / Notatka

Ta funkcja zostanie usunięta w przyszłej wersji programu SQL Server. Unikaj używania tej funkcji w nowych pracach programistycznych i zaplanuj modyfikowanie aplikacji, które obecnie korzystają z tej funkcji.

Ograniczenia i ograniczenia

  • Jeśli dodasz, zmodyfikujesz lub usuniesz zapis logiczny po zainicjowaniu subskrypcji publikacji, musisz wygenerować nowy snapshot i ponownie zainicjować wszystkie subskrypcje po wprowadzeniu zmiany. Więcej informacji o wymaganiach dotyczących zmian właściwości można znaleźć w temacie Zmienianie właściwości publikacji i artykułu.

Korzystanie z programu SQL Server Management Studio

Zdefiniuj logiczne rekordy w oknie dialogowym Dodaj dołącz, które jest dostępne w kreatorze Nowej Publikacji oraz w oknie Właściwości Publikacji - <Publikacja> . Aby uzyskać więcej informacji na temat korzystania z kreatora i uzyskiwania dostępu do okna dialogowego, zobacz Tworzenie publikacji i Wyświetlanie i modyfikowanie właściwości publikacji.

Logiczne rekordy można zdefiniować w oknie dialogowym Add Join tylko wtedy, gdy są stosowane do filtra łączenia w publikacji merge, a publikacja spełnia wymagania dotyczące użycia wstępnie obliczonych partycji. Aby zdefiniować rekordy logiczne, które nie są stosowane do filtrów stowarzyszeń oraz ustawić wykrywanie i rozwiązywanie konfliktów na poziomie rekordów logicznych, należy użyć procedur przechowywanych.

Aby zdefiniować logiczną relację rekordu

  1. Na stronie Filtrowanie wierszy tabeli w Kreatorze nowej publikacji lub na stronie Filtrowanie wierszy w oknie dialogowym Właściwości publikacji — <Publikacja> wybierz filtr wierszy w panelu Filtrowane tabele.

    Logiczne powiązanie rekordu jest powiązane z filtrem skojarzenia, który rozszerza filtr wierszowy. Dlatego musisz zdefiniować filtr wierszy, zanim będzie można rozszerzyć go o złączenie i zastosować logiczną relację między rekordami. Po zdefiniowaniu jednego filtra łączenia można go rozszerzyć o inny filtr połączenia. Więcej informacji o definiowaniu filtrów łączenia można znaleźć w artykule Zdefiniuj i zmodyfikuj filtr łączenia między artykułami scalania.

  2. Kliknij Dodaj się, a następnie Dodaj dołącz, aby rozszerzyć wybrany filtr.

  3. Zdefiniuj filtr łączenia w oknie dialogowym Dodaj dołączenie , a następnie zaznacz pole Logiczny rekord.

  4. Jeśli jesteś w oknie dialogowym Właściwości publikacji — <Publikacja>, kliknij przycisk OK, aby zapisać zmiany i zamknąć okno dialogowe.

Usuwanie logicznego powiązania rekordu

  • Usuń tylko relację logicznego rekordu lub usuń powiązanie logicznego rekordu i powiązany z nią filtr dołączenia.

    Aby usunąć tylko relację logicznego rekordu:

    1. Na stronie Filtrowanie wierszy w Kreatorze nowej publikacji lub na stronie Filtrowanie wierszy w oknie dialogowym Właściwości publikacji — <Publikacja> wybierz filtr sprzężenia powiązany z logiczną relacją rekordów w panelu Filtrowane tabele, a następnie kliknij przycisk Edytuj.

    2. W oknie dialogowym Edytuj Dołączenie usuń pole Logiczny rekord.

    3. Kliknij przycisk OK.

    Aby usunąć powiązanie logicznego rekordu i filtr łączenia z nim powiązany:

    • Na stronie Filtrowanie wierszy w Kreatorze nowej publikacji lub w oknie dialogowym Właściwości publikacji — <Publikacja> wybierz filtr w okienku Filtrowane tabele, a następnie kliknij przycisk Usuń. Jeśli filtr joinów, który usuniesz, sam zostanie rozszerzony o inne joiny, te joiny również zostaną usunięte.

Korzystanie z Transact-SQL

Możesz programowo określić logiczne relacje rekordów między artykułami za pomocą procedur przechowywanych w replikacji.

Aby zdefiniować logiczne powiązanie rekordu bez powiązanego filtra łączenia

  1. Jeśli publikacja zawiera artykuły filtrowane, wykonaj sp_helpmergepublication i zanotuj wartość use_partition_groups w zbiorze wyników.

    • Jeśli wartość wynosi 1, to już są używane wcześniej obliczone partycje.

    • Jeśli wartość wynosi 0, uruchom sp_changemergepublication na serwerze Publisher w bazie danych publikacji. Określmy wartość use_partition_groups dla @property oraz wartość true dla @value.

      Uwaga / Notatka

      Jeśli publikacja nie obsługuje partycji wstępnie obliczonych, nie można używać zapisów logicznych. Więcej informacji można znaleźć w temacie Wymagania dotyczące używania wstępnie obliczonych partycji w sekcji Optymalizacja wydajności filtrowania parametryzowanego przy użyciu wstępnie obliczonych partycji.

    • Jeśli wartość jest NULL, to Snapshot Agent musi zostać uruchomiony, aby wygenerować początkowy snapshot dla publikacji.

  2. Jeśli artykuły, które będą tworzyć rekord logiczny, nie istnieją, wykonaj sp_addmergearticle u wydawcy w bazie danych publikacji. Określ jedną z następujących opcji wykrywania i rozwiązywania konfliktów dla rekordu logicznego:

    • Aby wykryć i rozwiązać konflikty występujące w powiązanych wierszach w rekordzie logicznym, określ wartość true dla @logical_record_level_conflict_detection i @logical_record_level_conflict_resolution.

    • Aby użyć standardowego wykrywania i rozwiązywania konfliktów na poziomie wiersza lub kolumny, należy określić wartość falsz dla @logical_record_level_conflict_detection i @logical_record_level_conflict_resolution, co jest domyślne.

  3. Powtórz krok 2 dla każdego artykułu, który będzie stanowił logiczny zapis. Musisz użyć tej samej opcji wykrywania i rozwiązywania konfliktów dla każdego artykułu w logicznym rekordzie. Aby uzyskać więcej informacji, zobacz Wykrywanie i rozwiązywanie konfliktów w rekordach logicznych.

  4. Na serwerze wydawcy, w bazie danych publikacji, wykonaj sp_addmergefilter. Określ @publication, nazwę jednego artykułu w relacji dla @article, nazwę drugiego artykułu dla @join_articlename, nazwę relacji dla @filtername, klauzulę definiującą relację między dwoma artykułami dla @join_filterclause, typ łączenia dla @join_unique_key oraz jedną z następujących wartości dla @filter_type:

    • 2 - Definiuje zależność logiczną.

    • 3 - Definiuje logiczne powiązanie z filtrem łączenia.

    Uwaga / Notatka

    Jeśli filtr łączenia nie jest używany, kierunek relacji między dwoma artykułami nie ma znaczenia.

  5. Powtórz krok 2 dla każdej pozostałej relacji między rekordami logicznymi w publikacji.

Zmiana wykrywania i rozstrzygania konfliktów dla rekordów logicznych

  1. Aby wykryć i rozwiązać konflikty występujące w powiązanych wierszach w rekordzie logicznym:

    • W Publisher w bazie danych publikacji wykonaj sp_changemergearticle. Określ wartość logical_record_level_conflict_detection dla @property oraz wartość true dla @value. Określ wartość 1 dla @force_invalidate_snapshot i @force_reinit_subscription.

    • W Publisher w bazie danych publikacji wykonaj sp_changemergearticle. Określ wartość logical_record_level_conflict_resolution dla @property oraz wartość true dla @value. Określ wartość 1 dla @force_invalidate_snapshot i @force_reinit_subscription.

  2. Aby użyć standardowego wykrywania i rozwiązywania konfliktów na poziomie wiersza lub kolumny:

    • W Publisher w bazie danych publikacji wykonaj sp_changemergearticle. Określ wartość logical_record_level_conflict_detection dla @property oraz wartość false dla @value. Określ wartość 1 dla @force_invalidate_snapshot i @force_reinit_subscription.

    • W Publisher w bazie danych publikacji wykonaj sp_changemergearticle. Określ wartość logical_record_level_conflict_resolution dla @property oraz wartość false dla @value. Określ wartość 1 dla @force_invalidate_snapshot i @force_reinit_subscription.

Aby usunąć logiczne powiązanie rekordu

  1. W Publisher w bazie publikacji wykonaj następujące zapytanie, aby zwrócić informacje o wszystkich logicznych relacjach rekordów zdefiniowanych dla określonej publikacji:

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

    Zwróć uwagę na nazwę usuwanej relacji rekordu logicznego w kolumnie filtername w zbiorze wyników.

    Uwaga / Notatka

    To zapytanie zwraca te same informacje co sp_helpmergefilter; jednak ta procedura przechowywana w systemie zwraca jedynie informacje o logicznym powiązaniach rekordów, które również są filtrami stowarzyszeń.

  2. Na serwerze Publisher w bazie danych publikacji wykonaj sp_dropmergefilter. Określ @publication, nazwę jednego z artykułów w ramach relacji dla @article oraz nazwę relacji z kroku 1 dla @filtername.

Przykład (Transact-SQL)

Ten przykład włącza wstępnie obliczone partycje dla istniejącej publikacji i tworzy rekord logiczny składający się z dwóch nowych artykułów dla tabel SalesOrderHeader i 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

Korzystanie z obiektów zarządzania replikacją (RMO)

Uwaga / Notatka

Replikacja scalania umożliwia określenie, aby konflikty były śledzone i rozwiązywane na poziomie rekordu logicznego, ale tych opcji nie można ustawić za pomocą RMO.

Aby zdefiniować logiczne powiązanie rekordu bez powiązanego filtra łączenia

  1. Utwórz połączenie z programem Publisher przy użyciu klasy ServerConnection.

  2. Utwórz instancję klasy MergePublication, ustaw właściwości Name i DatabaseName dla publikacji oraz ustaw właściwość ConnectionContext na połączenie utworzone w kroku 1.

  3. Wywołaj metodę LoadProperties, aby uzyskać właściwości obiektu. Jeśli ta metoda zwraca false, właściwości publikacji w kroku 2 zostały niepoprawnie zdefiniowane lub publikacja nie istnieje.

  4. Jeśli właściwość PartitionGroupsOption jest ustawiona na False, ustaw ją na True.

  5. Jeśli artykuły tworzące rekord logiczny nie istnieją, stwórz instancję MergeArticle klasy i ustaw następujące właściwości:

    • Nazwa artykułu dla Name.

    • Nazwa publikacji dla PublicationName.

    • (Opcjonalnie) Jeśli artykuł jest filtrowany poziomo, określ klauzulę filtra wierszowego dla tej FilterClause właściwości. Użyj tej właściwości, aby określić statyczny lub parametryzowany filtr wierszowy. Aby uzyskać więcej informacji, zobacz Sparametryzowane filtry wierszy.

    Aby uzyskać więcej informacji, zobacz Definiowanie artykułu.

  6. Wywołaj metodę Create .

  7. Powtórz kroki 5 i 6 dla każdego artykułu tworzącego zapis logiczny.

  8. Stwórz instancję klasy MergeJoinFilter , aby zdefiniować logiczne powiązania rekordów między artykułami. Następnie ustaw następujące właściwości:

  9. Wywołaj metodę AddMergeJoinFilter dla obiektu, który reprezentuje artykuł podrzędny w relacji. Przekaż MergeJoinFilter obiekt z kroku 8, aby zdefiniować relację.

  10. Powtórz kroki 8 i 9 dla każdej z pozostałych relacji rekordów logicznych w publikacji.

Przykład (RMO)

Ten przykład tworzy logiczny rekord obejmujący dwa nowe rekordy dla tabel SalesOrderHeader i 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