Share via


Langfristige Datenspeicherung

Langfristige Datenaufbewahrung automatisiert den Transfer von Daten aus Ihrer Microsoft Dataverse-Transaktionsdatenbank zu einem verwalteten Data Lake für kosteneffiziente Archivspeicherung. Beginnen Sie mit dem Konfigurieren von Tabellen für Langzeitaufbewahrung. Erstellen Sie dann Aufbewahrungsrichtlinien, die die zu archivierenden Daten definieren. Geplante Aufbewahrungsläufe übertragen Zeilen, die den Kriterien entsprechen.

Wichtig

Um alle Funktionen zur Langzeitdatenaufbewahrung nutzen zu können, müssen Sie die beiden hier beschriebenen Anforderungen erfüllen: Übersicht über die Langzeitdatenaufbewahrung in Dataverse.

Eine Aufbewahrungsrichtlinie einrichten

Verwenden Sie zum Erstellen von Aufbewahrungsrichtlinien unsere APIs, das Maker Portal oder die Lösungsinstallation. Das folgende Codebeispiel demonstriert die Verwendung von APIs zur Erstellung eines Aufbewahrungsrichtlinie.

Der folgende Code verwendet den Organisationsdienst und die IOrganizationService.Create(Entity)-Methode, um eine Aufbewahrungsrichtlinie zu erstellen, die alle geschlossenen Verkaufschancen aufbewahrt und jährlich ausgeführt wird. Gültige Wiederholungsparameter sind DAILY, WEEKLY, MONTHLY und YEARLY. Um die Aufbewahrung nur einmal auszuführen, setzen Sie den Wiederholungswert auf leer.

public void CreateRetentionConfig(IOrganizationService orgService)
{
    Entity retentionConfig = new Entity("retentionconfig");
    retentionConfig["retentionconfigid"] = Guid.NewGuid();
    retentionConfig["entitylogicalname"] = "incident";
    retentionConfig["name"] = "Retain all closed opportunities";
    retentionConfig["uniquename"] = "ui_RetainAllClosedOpportunities";
    retentionConfig["statecode"] = new OptionSetValue(0);
    retentionConfig["statuscode"] = new OptionSetValue(10);
    retentionConfig["criteria"] = "<fetch version=\"1.0\" output-format=\"xml-platform\" mapping=\"logical\" distinct=\"false\"> " +
        "<entity name=\"opportunity\"> " +
            "<attribute name=\"name\" /> " +
            "<attribute name=\"statecode\" />" +
            "<attribute name=\"actualvalue\" />" +
            "<attribute name=\"actualclosedate\" />" +
            "<attribute name=\"customerid\" />" +
            "<attribute name=\"opportunityid\" />" +
            "<order attribute=\"actualclosedate\" descending=\"true\" />" +
            "<filter type=\"and\">" +
                "<filter type=\"or\">" +
                    "<condition attribute=\"statecode\" operator=\"eq\" value=\"1\" />" +
                    "<condition attribute=\"statecode\" operator=\"eq\" value=\"2\" />" +
                "</filter>" +
            "</filter>" +
        "</entity></fetch>";
    retentionConfig["starttime"] = DateTime.Parse("2024-05-01T00:00:00");
    retentionConfig["recurrence"] = "FREQ=YEARLY;INTERVAL=1";
    try
    {
        var retentionConfigId = orgService.Create(retentionConfig);
        Console.WriteLine($"Retention policy created with Id : {retentionConfigId}");
    }
    catch (Exception ex)
    {
        throw new Exception($"Create retention policy failed: {ex.Message})", ex);
    }
}

Die Ausgabe dieses Codes lautet „Aufbewahrungsrichtlinie erstellt mit Id : c1a9e932-89f6-4f17-859c-bd2101683263“.

Überprüfen Sie Ihre Aufbewahrungsrichtlinie

Der Prozess der Langzeitaufbewahrung verschiebt Daten vom Dataverse-Transaktionsspeicher in einen verwalteten Data Lake. Sie können keine Transaktionsvorgänge mehr auf den Daten ausführen, nachdem diese in den Data Lake verschoben wurden. Es ist wichtig, sicherzustellen, dass Ihre Aufbewahrungsrichtlinien korrekt sind. Sie können Ihre eigenen Validierungen hinzufügen, indem Sie optional ein angepasstes Plug-in für die Nachricht ValidateRetentionConfig registrieren.

class SampleValidateRetentionConfigPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var entityName = pluginContext.PrimaryEntityName;
        if( pluginContext.InputParameters.TryGetValue("FetchXml", out var fetchXml) )
        {
            // Add custom validation against the Fetch XML. 
        }
        else
        {
            throw new Exception("No critiera provided.");
        }
    }
}

Angepasste Logik, wenn die Speicherung ausgeführt wird

Die langfristige Aufbewahrung ist ein asynchroner Prozess, der immer dann ausgeführt wird, wenn eine Richtlinie zur Aufbewahrung festgelegt wird. Es werden die folgenden Vorgänge ausgeführt:

  1. Markieren Sie Zeilen (Datensätze), die für die Aufbewahrung bereit sind.
  2. Kopieren Sie die markierten Zeilen in den Data Lake.
  3. Bereinigen von Zeilen aus der Quelldatenbank.
  4. Führen Sie ein Rollback der markierten Zeilen durch, wenn die Bereinigung fehlschlägt.

Sie können optional benutzerdefinierte Plug-Ins registrieren, die ausgeführt werden, wenn Zeilen zur Aufbewahrung markiert werden, wenn Zeilen an der Quelle gelöscht werden oder wenn für zur Aufbewahrung markierte Zeilen ein Rollback durchgeführt wird. Das Schreiben von Plug-in Code gilt nur für SDK für .NET Programmierung. Die Web-API unterstützt nicht die Plug-In-Entwicklung.

Angepasste Logik, wenn eine Zeile zur Speicherung markiert wird

Im Rahmen der Markierung von Zeilen zur Aufbewahrung ruft Dataverse die Nachrichten BulkRetain und Retain auf. Sie können benutzerdefinierte Logik hinzufügen, indem Sie bei der Ausführung dieser Nachrichten ein Plug-In registrieren. Beispiele für benutzerdefinierte Logik sind das Markieren weiterer Zeilen zur Aufbewahrung oder das Durchführen einer Validierung, bevor Zeilen zur Aufbewahrung markiert werden

Dieses Codebeispiel zeigt ein benutzerdefiniertes Plug-In, das während der Aufbewahrung einer einzelnen Tabellenzeile ausgeführt wird.

class SampleRetainPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var entityName = pluginContext.PrimaryEntityName;
        if( pluginContext.InputParameters.TryGetValue("Target", out var _target) )
        {
            EntityReference target = (EntityReference)_target;
            Console.WriteLine($"Request came for table : {target.Name} with id : {target.Id}");
            // Add your logic for validation or additional operation. 
            // For example - you can call Retain on Additional row of another table. 
        }
        else
        {
            throw new Exception("No target present.");
        }
    }
}

Für einen Rollback Retain-Vorgang schreiben Sie Ihr Plugin ähnlich wie im obigen Beispiel, außer dass Sie es auf die Nachricht RollbackRetain registrieren.

Angepasste Logik bei Bulk Retain

Dieses Codebeispiel demonstriert eine benutzerdefinierte Logik bei der Ausführung eines BulkRetain-Nachrichtenvorgangs auf der letzten Seite

class SampleBulkRetainPlugin : IPlugin
{
    // Send notification when bulk retain execution is done. 
    public void Execute(IServiceProvider serviceProvider)
    {
        var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var entityName = pluginContext.PrimaryEntityName;
        if(pluginContext.OutputParameters != null 
            && pluginContext.OutputParameters.TryGetValue("HasMoreRecords", out var _hasMoreRecords) )
        {    
            if(!(bool)_hasMoreRecords)
            {
                Console.WriteLine("This is a last execution of this request.");
                // SendNotifcation that retention for an entity is completed. 
            }
        }
    }
}

Benutzerdefinierte Logik, wenn eine Zeile aufgrund einer Aufbewahrung gelöscht wird

Dataverse führt die Nachricht PurgeRetainedContent aus, um die Zeilen mit Transaktionsdaten zu löschen, die erfolgreich in den Data Lake verschoben wurden. Die PurgeRetainedContent-Nachricht führt intern einen Delete-Nachrichtenvorgang aus, um die Tabellenzeilen zu löschen, die erfolgreich verschoben wurden

Sie können ein benutzerdefiniertes Plug-In für die PurgeRetainedContent-Nachricht registrieren, wenn Sie während des Bereinigungsvorgangs auf Tabellenebene eine benutzerdefinierte Logik benötigen. Optional können Sie ein benutzerdefiniertes Plug-In für die Delete-Nachricht registrieren, wenn Sie Code aufrufen müssen, wenn eine Zeile aufgrund der Aufbewahrung gelöscht wird. Sie können ermitteln, ob die Löschung aufgrund einer Aufbewahrung erfolgte oder nicht, indem Sie die Eigenschaft ParentContext des Plug-Ins prüfen. Der Eigenschaftswert ParentContext für den Vorgang der Nachricht Delete aufgrund der Speicherung lautet „PurgeRetainedContent.“

Dieses Codebeispiel blockiert die Bereinigung einer Tabelle, wenn die Zeilen nicht zur Bereinigung bereit sind

class SamplePurgeRetainedContentPlugin : IPlugin
{
    // Block purge if all the rows are not validatd. 
    public void Execute(IServiceProvider serviceProvider)
    {
        var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var entityName = pluginContext.PrimaryEntityName;
        if( pluginContext.InputParameters.TryGetValue("MaxVersionToPurge", out var _maxVersiontoPurge) )
        {
            long MaxVersionToPurge = (long)_maxVersiontoPurge;
            var rowsToBePurged = GetToBePurgedRows(entityName, MaxVersionToPurge);
            // Add custom validation to process rowsToBePurged.
        }
    }

    public EntityCollection GetToBePurgedRows(string  entityName, long maxVersionToPurge)
    {
        IOrganizationService organizationService; // Create OrgService. 
        QueryExpression queryExpression = new QueryExpression()
        {
            EntityName = entityName,
            ColumnSet = new ColumnSet(new string[] { "versionnumber", "msft_datastate" })
        };
        queryExpression.Criteria.AddCondition("msft_datastate", ConditionOperator.Equal, 1);
        queryExpression.Criteria.AddCondition("versionnumber", ConditionOperator.LessEqual, maxVersionToPurge);
        var response = organizationService.RetrieveMultiple(queryExpression);
        return response;
    }
}

Dieses Codebeispiel gilt für den Löschvorgang aufgrund der Aufbewahrung

class SampleDeletePlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        if (IsDeleteDueToRetention(serviceProvider))
        {
            // Write your code to handle delete during retention
        }
        else
        {
            // Write your code to handle normal delete without retention
        }
    }

    private bool IsDeleteDueToRetention(IServiceProvider serviceProvider)
    {
        var currentContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        while (currentContext != null)
        {
            if (string.Equals(currentContext.MessageName, "PurgeRetainedContent"))
            {
                return true;
            }
            else
            {
                currentContext = currentContext.ParentContext;
            }
        }
        return false;
    }
}

Abfragen von Aufbewahrungsrichtlinien und Ausführungsdetails

Die Details der Aufbewahrungsrichtlinien werden in der Tabelle RetentionConfig gespeichert. Details zur Ausführung der Aufbewahrung werden in den Tabellen RetentionOperation und RetentionOperationDetail gespeichert. Sie können diese Tabellen abfragen, um die Richtlinien und Ausführungsdetails zu erhalten.

Der folgende Code liefert einige Beispiele von FetchXML, die zum Abfragen der Tabellenzeilen zu den Datumsaufbewahrungsdetails verwendet werden können. FetchXML ist eine proprietäre XML-basierte Abfragesprache. Sie kann mit SDK-basierten Abfragen mithilfe von FetchExpression verwendet werden und von der Web-API mithilfe der fetchXml-Abfragezeichenfolge

Dieses Codebeispiel zeigt eine einfache Abfrage zum Zurückgeben aller aktiven Aufbewahrungsrichtlinien für eine E-Mail-Bestellung nach Namen.


public EntityCollection GetActivePolicies(IOrganizationService orgService)
{
    string fetchXml = @"
    <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
      <entity name='retentionconfig'>
        <attribute name='retentionconfigid' />
        <attribute name='name' />
        <attribute name='createdon' />
        <attribute name='starttime' />
        <attribute name='recurrence' />
        <attribute name='entitylogicalname' />
        <attribute name='criteria' />
        <order attribute='name' descending='false' />
        <filter type='and'>
          <condition attribute='entitylogicalname' operator='eq' value='email' />
          <condition attribute='statuscode' operator='eq' value='10' />
        </filter>
      </entity>
    </fetch>";

    var query = new FetchExpression(fetchXml);

    EntityCollection results = orgService.RetrieveMultiple(query);

    results.Entities.ToList().ForEach(x => {
      Console.WriteLine(x.Attributes["name"]);
    });

    return(results);
}

Weitere Beispiele für FetchXML-Abfragezeichenfolgen

Dieses Codebeispiel veranschaulicht die Verwendung einer FetchXML-Anweisung zum Abrufen aller angehaltenen Aufbewahrungsrichtlinien für eine E-Mail.

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="retentionconfig">
    <attribute name="retentionconfigid" />
    <attribute name="name" />
    <attribute name="createdon" />
    <attribute name="starttime" />
    <attribute name="recurrence" />
    <attribute name="entitylogicalname" />
    <attribute name="criteria" />
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="entitylogicalname" operator="eq" value="email" />
      <condition attribute="statuscode" operator="eq" value="20" />
    </filter>
  </entity>
</fetch>

Dieses Codebeispiel zeigt, wie Sie mit einer FetchXML-Anweisung alle Aufbewahrungsvorgänge für eine Aufbewahrungsrichtlinie abrufen.

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="retentionoperation">
    <attribute name="retentionoperationid" />
    <attribute name="name" />
    <attribute name="statuscode" />
    <attribute name="statecode" />
    <attribute name="starttime" />
    <attribute name="rootentitylogicalname" />
    <attribute name="endtime" />
    <attribute name="criteria" />
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="retentionconfigid" operator="eq" uiname="All closed opportunities" uitype="retentionconfig" value="{35CC1317-20B7-4F4F-829D-5D9D5D77F763}" />
    </filter>
  </entity>
</fetch>

Dieses Codebeispiel zeigt eine FetchXML-Anweisung, die Details für einen Aufbewahrungsvorgang abruft.

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="retentionoperationdetail">
    <attribute name="retentionoperationdetailid" />
    <attribute name="name" />
    <attribute name="createdon" />
    <attribute name="retentionoperationid" />
    <attribute name="retentioncount" />
    <attribute name="isrootentity" />
    <attribute name="failedcount" />
    <attribute name="entitylogicalname" />
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="retentionoperationid" operator="eq"  uitype="retentionoperation" value="{35CC1317-20B7-4F4F-829D-5D9D5D77F763}"/>
    </filter>
  </entity>
</fetch>

Dieses Codebeispiel veranschaulicht die FetchXML-Anweisung, die Details zu einem Fehler abruft, der während eines Aufbewahrungsvorgangs aufgetreten ist.

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="retentionfailuredetail">
    <attribute name="retentionfailuredetailid" />
    <attribute name="name" />
    <attribute name="createdon" />
    <attribute name="recordid" />
    <attribute name="operation" />
    <attribute name="message" />
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="operationid" operator="eq" value="35CC1317-20B7-4F4F-829D-5D9D5D77F763" />
    </filter>
  </entity>
</fetch>

Siehe auch

Verwalten Sie Richtlinien zur Datenaufbewahrung
Langfristig gespeicherte Daten anzeigen
Löschen von Datensätzen in einem Massenvorgang
Verwenden der Microsoft Dataverse-Web-API

Hinweis

Können Sie uns Ihre Präferenzen für die Dokumentationssprache mitteilen? Nehmen Sie an einer kurzen Umfrage teil. (Beachten Sie, dass diese Umfrage auf Englisch ist.)

Die Umfrage dauert etwa sieben Minuten. Es werden keine personenbezogenen Daten erhoben. (Datenschutzbestimmungen).