長期データ保持に関する概要

長期的なデータ保持は、Microsoft Dataverse トランザクション データベースから管理されたデータレイクへのデータ転送を自動化し、コスト効率の高いアーカイブ ストレージを実現します。 テーブルを長期保存するように構成することから始めましょう。 次に、アーカイブするデータを定義する保持ポリシーを作成します。 スケジュールされた保持実行により、条件に一致する行が転送されます。

重要

すべての長期データ保持機能を使用するには、Dataverse 長期データ保持の概要 で説明されている要件を両方とも満たす必要があります。

保持ポリシーを設定する

保持ポリシーを作成するには、API、Maker Portal、またはソリューションのインストールを使用します。 次のコードサンプルは、API を使用して保持ポリシーを作成する例を示しています。

次のコードでは、Organization サービスIOrganizationService.Create(Entity) メソッドを使用して、クローズした営業案件をすべて保持し、1 年ごとに実行する保持ポリシーを作成します。 有効な繰り返しパラメータは DAILYWEEKLYMONTHLYYEARLY です 。 保持を 1 回だけ実行するには、繰り返し値を空に設定します。

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

このコードの出力は、「ID : c1a9e932-89f6-4f17-859c-bd2101683263 で作成された保持ポリシー」です。

保持ポリシーを検証する

長期保存プロセスにより、データは Dataverse のトランザクション ストレージから管理されたデータ レイクに移動します。 データがデータ レイクに移動された後は、そのデータに対してトランザクション操作を実行できなくなります。 保持ポリシーが正しいことを確認することが重要です。 オプションでカスタム プラグイン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. マークされた行をデータ レイクにコピーします。
  3. ソース データベースから行を消去します。
  4. パージが失敗した場合は、マークされた行をロールバックします。

オプションで、行が保持対象としてマークされているとき、行がソースで消去されているとき、または保持対象としてマークされている行がロールバックされているときに実行するカスタム プラグインを登録できます。 プラグイン コードの作成は、SDK for .NET プログラミングにのみ適用されます。 Web API はプラグイン開発をサポートしていません。

行が保持対象としてマークされている場合のカスタム ロジック

行を保持対象としてマークする一環として、Dataverse は BulkRetainRetain メッセージを呼び出します。 これらのメッセージの実行時にプラグインを登録することで、カスタム ロジックを追加できます。 カスタム ロジックの例には、保持する行をさらにマークしたり、行を保持対象としてマークする前に検証を実行したりすることが含まれます

このコード サンプルは、単一のテーブル行の保持中に実行されるカスタム プラグインを示しています。

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 メッセージを実行し、データ レイクへの移動に成功したトランザクション データの行を削除します。 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 ベースのクエリ言語です。 これは、FetchExpression SDK ベースのクエリと fetchXml クエリ文字列を使用した Web API で使用できます

このコード サンプルは、電子メール オーダーのすべてのアクティブな保持ポリシーを名前で返す簡単なクエリを示しています。


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

FetchXML クエリ文字列のほかの例

このコード サンプルは、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="20" />
    </filter>
  </entity>
</fetch>

このコード サンプルは、FetchXML ステートメントを使用して保持ポリシーのすべての保持操作を取得する方法を示しています。

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

このコードサンプルは、保持操作の詳細を取得する FetchXML ステートメントを示しています。

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

このコード サンプルは、保持操作中に発生した不具合/エラーの詳細を取得する FetchXML ステートメントを示しています。

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

参照

データ保持ポリシーを管理する
長期保存されたデータを表示する
データの一括削除
Microsoft Dataverse Web API を使用する

注意

ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)

この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。