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.
Abrufen aufbewahrter Daten
Sie können gespeicherte Daten mit FetchXml und QueryExpression abrufen.
Setzen Sie mit FetchXml den Attributwert des Fetch-Elements datasource
auf "retained"
.
<fetch datasource="retained">
<entity name="account">
<attribute name="accountId" />
</entity>
</fetch>
Setzen Sie mit QueryExpression die Eigenschaft QueryExpression.DataSource auf retained
.
Hinweis
Derzeit gibt es keine Möglichkeit, gespeicherte Daten mithilfe der Dataverse Web-API abzurufen.
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> " +
"<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:
- Markieren Sie Zeilen (Datensätze), die für die Aufbewahrung bereit sind.
- Kopieren Sie die markierten Zeilen in den Data Lake.
- Bereinigen von Zeilen aus der Quelldatenbank.
- 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>
<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>
<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>
<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"
value="{35CC1317-20B7-4F4F-829D-5D9D5D77F763}" />
</filter>
</entity>
</fetch>
Dieses Codebeispiel zeigt eine FetchXML-Anweisung, die Details für einen Aufbewahrungsvorgang abruft.
<fetch>
<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" 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>
<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).