2

最近、 Colectica SDK for DDIを使用するスクリプトを使用して 100 を超えるコンセプト アイテムを更新する必要があり、既知のルート プロジェクト アイテムを含むセット内のすべての場所にそれらの更新を伝達する必要があります。つまり、概念の古いバージョンを参照している各アイテムは、新しいバージョンを参照するように更新する必要があります。これにより、参照アイテムの新しいバージョンが作成され、その更新をセット内で同様に伝播する必要があります。

私の最善の解決策は、 の実装を使用してIVersionableVisitor古い参照を更新し、必要に応じて項目をダーティにマークすることです。この時点で、DirtyItemGatherer訪問者を使用してアイテムを収集および公開できます。これは 1 回のパスでは機能しませんが、更新する必要のあるアイテムがなくなるまで実行できることを期待していました。

internal class ReferencedVersionUpdaterVisitor : IVersionableVisitor
{
    public ReferencedVersionUpdaterVisitor(WcfRepositoryClient repositoryClient)
    {
        this.RepositoryClient = repositoryClient;
        this.VisitedLog = new Dictionary<Tuple<Guid, string>,bool>();
        this.Context = new List<IVersionable>();
    }

    private WcfRepositoryClient RepositoryClient { get; set; }

    private Dictionary<Tuple<Guid, string>, bool> VisitedLog { get; set; }

    public bool HaveVisited(IdentifierTriple id)
    {
        var logId = Tuple.Create(id.Identifier, id.AgencyId);
        return this.VisitedLog.ContainsKey(logId) && this.VisitedLog[logId];
    }

    public void RegisterVisit(IdentifierTriple id)
    {
        this.VisitedLog[Tuple.Create(id.Identifier, id.AgencyId)] = true;
    }

    private List<IVersionable> Context { get; set; }

    public void BeginVisitItem(IVersionable item)
    {
        if (!this.HaveVisited(item.CompositeId) &&
            !this.Context.Any(contextItem => contextItem.CompositeId.Identifier.Equals(item.CompositeId.Identifier) && contextItem.CompositeId.AgencyId.Equals(item.CompositeId.AgencyId)))
        {
            if (!item.IsPopulated)
            {
                var previousVersion = item.Version;
                this.RepositoryClient.PopulateItem(item, true, ChildReferenceProcessing.Instantiate);
                if (previousVersion != item.Version)
                {
                    item.IsDirty = true;
                }
            }
            this.Context.Add(item);
        }
    }

    public void EndVisitItem(IVersionable item)
    {
        if (!this.HaveVisited(item.CompositeId))
        {
            this.Context.Remove(item);
            this.RegisterVisit(item.CompositeId);
        }
    }
}

残念ながら機能しません。セットには、古いバージョンの子を参照する親アイテムがまだ含まれているため、すべてのパスで同じアイテムが検出されます。アイテムを変更して途中で変更するなど、このアプローチを調整するためのアイデアに考えと努力を注いできましたEndVisitItem()が、実際の問題には対処していません。

基本的な問題は、訪問者がセットを歩くときに親アイテムを変更する必要があることだと思います。これはグラフであるため、現在のノードに到達するためにたまたま使用した参照項目ほど、実際には親はありません。プロパティを使用してこれを記録しようとしましContextたが、その内容は、コンテキスト リストの最後の項目が「親」参照項目であるという私の期待と常に一致するとは限りません。

Colectica Designer では、この問題は Navigator 構造を内部的に使用することで解決されていますが、残念ながら Colectica SDK では利用できないようです。また、Colectica Designer の Navigator ベースのソリューションは非常に優れたパフォーマンスを発揮しますが、このビジターのパフォーマンスは、 から Colectica リポジトリへのラウンドトリップが複数回行われるため、非常に低くなりますBeginVisitItem()。これは、私がこれについてすべて間違っているかもしれないかのように感じさせます. Colectica SDK で利用できるツールを使用してこれにアプローチするより良い方法はありますか?

また、すべての子アイテムに最新のデータを入力する機能を認識していることにも注意してください。ただし、そこから、すべてのダーティ アイテムの検索、バージョンのバンプ、保存、および更新の伝播の問題が、私はすでに解決しようとしています。

また、コンセプトや関連アイテムだけでなく、ルート化されたセット内のすべてを最新バージョンに更新することの副作用はまったく問題なく、実際には好まれる可能性があることも付け加えておきます.

4

1 に答える 1

2

これが私が最終的に思いついた解決策です。

オプションを使用してルート プロジェクト アイテムを取得することから始めInstantiateLatestます。

var testProject = repositoryClient.GetLatestItem(
    itemGuid,
    agencyId,
    ChildReferenceProcessing.InstantiateLatest);

次にMarkUpdatedReferencesDirtyVisitor、ルート アイテムに a を送信します (この訪問者のコードは、この回答の最後に含まれています)。

var markUpdatedReferencesDirtyVisitor =
    new MarkUpdatedReferencesDirtyVisitor(repositoryClient);
testProject.Accept(markUpdatedReferencesDirtyVisitor);

これに続いて、汚れていないアイテムを収集するオプションなしで訪問者を送信しDirtyItemGathererますが、汚れたアイテムの汚れた親としてマークするオプションを指定します。

var dirtyItemGatherer = new DirtyItemGatherer(false, true);
testProject.Accept(dirtyItemGatherer);

WcfRepositoryClient.RegisterItems()この時点で、 を呼び出して更新を公開する前に、ダーティ アイテムのバージョン番号を上げたり、サニティ チェックを行ったりするなど、いくつかの基本的なボイラープレート処理を実行する必要があります。

のコードは次のとおりですMarkUpdatedReferencesDirtyVisitor。基本的な考え方は、各アイテムの子の最新バージョンを取得し、それらを現在の子バージョンと比較することです。違いがある場合は、アイテムをダーティとしてマークします。その後、最新の子を含むバージョンが公開されます。

internal class MarkUpdatedReferencesDirtyVisitor : VersionableVisitorBase
{
    public MarkUpdatedReferencesDirtyVisitor(
        WcfRepositoryClient repositoryClient)
    {
        this.RepositoryClient = repositoryClient;
    }

    private WcfRepositoryClient RepositoryClient { get; set; }

    public override void BeginVisitItem(IVersionable item)
    {
        if (!this.HaveVisited(item.CompositeId) && !item.IsDirty)
        {
            base.BeginVisitItem(item);
            if (!item.IsPopulated)
            {
                this.RepositoryClient.PopulateItem(
                    item,
                    true,
                    ChildReferenceProcessing.InstantiateLatest);
            }
            var latestChildren = item.GetChildren();
            var currentChildren = this.RepositoryClient.GetItem(
                    item.CompositeId,
                    ChildReferenceProcessing.Instantiate).GetChildren();
            if (latestChildren.Count != currentChildren.Count)
            {
                item.IsDirty = true;
            }
            else
            {
                for(int i = 0; i < currentChildren.Count; i++)
                {
                    if (!latestChildren[i].CompositeId.Equals(
                        currentChildren[i].CompositeId))
                    {
                        item.IsDirty = true;
                        break;
                    }
                }
            }
        }
    }
}

これは私が望んでいたほど効率的ではありませんが、1 回のパスで機​​能するため、パフォーマンスは許容範囲内です。

于 2013-10-28T11:30:06.050 に答える