Tridion 删除链接到多个项目的组件

Tridion 删除链接到多个项目的组件,tridion,Tridion,我有一个链接到数千个项目的组件(在本例中,所有其他项目都是组件)。是否有简单/快速的方法删除组件并删除所有链接 我目前正在使用Tridion5.3,并通过TomAPI以编程方式完成这项工作。对于链接到10000个其他组件的一个组件,这大约需要7个小时。我还有很多要去 我正在从R5.3迁移到2011的过程中,因此可以使用其中任何一个来完成任务 我使用的代码如下 static void Main(string[] args) { var componentIDToRemove = "tcm:

我有一个链接到数千个项目的组件(在本例中,所有其他项目都是组件)。是否有简单/快速的方法删除组件并删除所有链接

我目前正在使用Tridion5.3,并通过TomAPI以编程方式完成这项工作。对于链接到10000个其他组件的一个组件,这大约需要7个小时。我还有很多要去

我正在从R5.3迁移到2011的过程中,因此可以使用其中任何一个来完成任务

我使用的代码如下

static void Main(string[] args)
{
    var componentIDToRemove = "tcm:4-123456";

    var linkedComponentIDs = System.IO.File.ReadAllLines("C:\\...\\whereused.txt"); // ids of the components linked to tcm:4-123456

    TDS.TDSE tdse = new TDS.TDSE();

    foreach (var linkedComponentID in linkedComponentIDs)
    {
        TDS.Component component = null;
        TDS.ItemFieldValues itemFieldValues = null;

        try
        {
            component = (TDS.Component)tdse.GetObject(linkedComponentID, TDSDefines.EnumOpenMode.OpenModeView);

            itemFieldValues = component.MetadataFields["myfield"].value;

            var itemFieldValuesCount = itemFieldValues.Count;
            for (var i = itemFieldValuesCount; i > 0; i--)
            {
                if (itemFieldValues[i].ID == componentIDToRemove)
                {
                    component.CheckOut();
                    itemFieldValues.Remove(i);
                    component.Save();
                    component.CheckIn();
                }
            }
        }
        finally
        {
            // release the TDS objects from memory
            ReleaseObject(component);
            ReleaseObject(itemFieldValues);
        }
    }
}

public static void ReleaseObject(object o)
{
    try
    {
        if (o != null)
        {
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o);
        }
    }
    finally
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

通过TOM使用脚本是最好的方法。Tridion2011中的核心服务API可能不会快很多

根据我的经验,以下是在.NET中通过互操作使用TOM的最佳实践

  • 显式声明所有对象并释放它们。例如:

    // do this
    var items = folder.GetItems(16);
    foreach(var item in items)
    {
        // ...
    }
    if(items != null)
    {
        Marshal.FinalReleaseComObject(items);
    }
    
    // instead of this
    foreach(var item in folder.GetItems(16))
    {
        // ...
    }
    
  • 如果将对象传递给方法-传递URI而不是对象,并在方法内声明对象的新实例,并在方法内显式释放它

  • 声明一个TDSE实例并引用它。创建多个实例是一个更昂贵的选项

  • 在何处使用可能需要很长时间,并且对数据库的要求很高。在运行代码之前更新数据库索引并运行维护脚本


每次处理组件时,您似乎都会触发两次垃圾回收。这几乎肯定会对你的表现产生很大影响


至于TOM,大多数重要的事情都是别人说的,尽管我认为没有人提到ItemField集合与使用XMLAPI来完成同样的工作相比速度非常慢。换句话说,使用GetXml()加载一个XmlDocument(或者XDocument)。。。直接操作XML,使用UpdateXml()将其推回并保存。

如果您对代码有疑问,请共享它,以便我们可以查看它。代码看起来不错。也许DBA可以在脚本运行时监视资源?在DB上运行脚本会更快,但可能会产生一些难以恢复的意外副作用。该组件中的链接是来自该组件还是来自其他组件?您是否知道要具体检查哪个字段(即,是否需要循环?)。您的组件是否可能在元数据中链接多次?如果是这样,您将反复签出、保存和签入。可能不是这样,但它可能会使事情加快一点。通常是“.Save()”占用了这些脚本的时间。也可以考虑使用.Stue(True),而不是每次检查。如果“目标观众”组件可以被重用或“模板”,则有意义,否则嵌入的模式和关键字可能就没那么疯狂了。据我所知,没有脚本,但如果您知道该组件通常存在的位置和/或作者在链接时有约定,您可能会获得一点性能提升。例如,如果链接的项目在列表中通常“较高”,您可能希望从0循环到
itemFieldValuesCount
。谢谢@robrtc。我已经在我的问题中发布了我的代码。我想我做的一切都对吗?就像我对Frank说的,我希望有一个我不知道的脚本/程序。你建议只在
组件上垃圾收集一次吗?(可能是组件收集了
itemFieldValues
)。或者你会把垃圾收集放在哪里?我没有在代码上运行探查器,只是一步一步地执行,垃圾收集会在调用TOM API时立即完成,但明显存在延迟。根本不要强制垃圾收集。让垃圾收集器来决定。在与步进调试器相关联的时间范围内,您不会注意到GC.Ok。因此不需要调用
GC.Collect()
GC.WaitForPendingFinalizers()?完全正确。这些方法由GC公开,供编写专家工具等的人员使用。您不需要用普通代码调用它们。