长期数据保留

长期数据保留可自动将数据从Microsoft Dataverse事务数据库传输到托管数据湖,以实现经济高效的存档存储。 首先 配置表以便长期保留。 然后,创建用于定义要存档的数据的保留策略。 计划的保留期运行与条件匹配的传输行。

Important

若要使用所有长期数据保留功能,必须满足 Dataverse 长期数据保留概述中所述的两项要求。

检索保留的数据

可以使用 FetchXml 和 QueryExpression 检索已保留的数据。

通过使用 FetchXml,将 fetch 元素datasource 属性值设置为 "retained".

<fetch datasource="retained">
   <entity name="account">
      <attribute name="accountId" />
   </entity>
</fetch>

通过使用 QueryExpression ,将 QueryExpression.DataSource 属性 设置为 retained。

Note

目前无法通过具有 OData 样式查询的 Dataverse Web API 检索保留的数据。 可以将 FetchXml 与 Dataverse Web API 配合使用。

设置保留策略

若要创建保留策略,请使用 API、创建者门户或解决方案安装。 下面的代码示例演示如何使用 API 创建保留策略。

以下代码使用 组织服务 和 IOrganizationService.Create(Entity) 方法 创建一个保留策略,用于保留所有已关闭的商机,并且每年运行一次。 有效的重复参数是DAILY,WEEKLYMONTHLY和YEARLY。 若要仅运行保留一次,请将重复周期值设置为空。

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);
    }
}

此代码的输出是“使用 Id 创建的保留策略:c1a9e932-89f6-4f17-859c-bd2101683263”。

验证保留策略

长期保留过程将数据从 Dataverse 事务存储移动到托管数据湖。 移动到 Data Lake 后,不能再对数据运行事务操作。 请务必确保保留策略正确。 您可以通过在 消息上可选地注册自定义 ValidateRetentionConfig 来添加自己的验证。

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.");
        }
    }
}

执行保留操作时的自定义逻辑

长期保留是一个异步过程,每当你设置保留策略时都会运行。 它执行以下操作:

  1. 标记准备保留的行(记录)。
  2. 将标记的行复制到 Data Lake。
  3. 清除源数据库中的各行数据。
  4. 如果清除失败,则回滚已标记的行。

您可以选择注册自定义插件,以便在行被标记为保留时、行在源端被清除时,或标记为保留的行被回滚时执行。 编写插件代码仅适用于用于 .NET 编程的 SDK。 Web API 不支持插件开发。

行被标记为保留时的自定义逻辑

作为标记行以供保留的一部分,Dataverse 调用 BulkRetain 和 Retain 消息。 可以通过在这些消息执行时注册插件来添加自定义逻辑。 自定义逻辑的示例包括标记更多行以供保留或执行验证,然后再将行标记为保留。

此代码示例演示在保留单个表行期间执行的自定义插件。

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.");
        }
    }
}

对于回滚保留操作,请参照前面的示例编写插件,只是要将其注册到 RollbackRetain 消息上。

批量保留中的自定义逻辑

此代码示例演示了在 BulkRetain 消息操作最后一页执行时的自定义逻辑。

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. 
            }
        }
    }
}

因保留而删除行时的自定义逻辑

Dataverse 执行 PurgeRetainedContent 消息以删除已成功移动到 Data Lake 的事务数据行。 PurgeRetainedContent 消息在内部执行 Delete 消息操作,以删除其已成功移动的表行。

如果您需要在表级清除操作期间实现自定义逻辑,可以在 PurgeRetainedContent 消息上注册自定义插件。 或者,如果您需要在某一行因保留策略而被删除时调用代码,则可以在 Delete 消息上注册自定义插件。 可以通过检查插件的 ParentContext 属性来确定删除是否由于保留而发生。 由于保留原因触发的 Delete 消息操作的 ParentContext 属性值为“PurgeRetainedContent”。

当行尚未准备好清除时,此代码示例会阻止对表进行清除。

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;
    }
}

此代码示例适用于由于保留而导致的删除操作。

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;
    }
}

查询保留策略和执行详细信息

系统将保留策略详细信息 RetentionConfig 存储在表中。 它将保留操作的详细信息存储在 RetentionOperation 和 RetentionOperationDetail 表中。 可以查询这些表以获取保留策略和执行详细信息。

下面的代码提供了一些 FetchXML 示例,可用于查询日期保留详细信息表行。 FetchXML 是基于 XML 的专有查询语言。 你可以在基于 SDK 的查询中使用 FetchExpression,也可以在 Web API 中通过 fetchXml 查询字符串使用它。

此代码示例演示了一个简单的查询,用于按名称返回电子邮件订单的所有活动保留策略。


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);
}

FetchXML 查询字符串的更多示例

此代码示例演示如何使用 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="20" />
    </filter>
  </entity>
</fetch>

此代码示例演示如何使用 FetchXML 语句检索保留策略的所有保留操作。

<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>

此代码示例显示一个 FetchXML 语句,该语句检索保留操作的详细信息。

<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>

此代码示例演示 FetchXML 语句,该语句检索有关在保留操作期间发生的失败的详细信息。

<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>

另见

管理数据保留策略
查看长期保留的数据
批量删除数据
使用 Microsoft Dataverse Web API