Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting a component linked to many items

Tags:

tridion

I have a component that is linked to many thousands of items (in this case all the other items are components). Is there an easy/fast way to delete the component and remove all the links?

I am currently using Tridion 5.3 and and doing this programmatically via the TOM API. For one component that was linked to 10000 other components this took about 7 hours. I have many more to go!

I am in the process of migrating from R5.3 to 2011 so can use either for the task.

The code I am using is as follows...

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();
    }
}
like image 725
Kevin Brydon Avatar asked Feb 18 '23 06:02

Kevin Brydon


2 Answers

Using a script via TOM is the best way to do it. The Core Service API in Tridion 2011 is probably not much faster.

From my experience the following are best practice when using TOM via Interop in .NET.

  • Explicitly declare all objects and release them. For example:

    // 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))
    {
        // ...
    }
    
  • If passing an object to a method - pass the URI instead of the object and declare a new instance of the object within the method and explicitly release it inside the method.

  • Declare a single instance of TDSE and reference it. Creating multiple instances is a more expensive option.

  • Where Used can take a long time and is heavy on the database. Update database indexes and run maintenance scripts before running the code.

like image 136
robrtc Avatar answered Mar 29 '23 18:03

robrtc


You appear to be triggering two garbage collections each time you process a component. This is almost certainly going to affect your performance quite a lot.

As for the TOM - most of the important things have been said by others, although I don't think anyone has mentioned that ItemField collections are incredibly slow when compared to using the XML API to do the same job. In other words, load an XmlDocument (or perhaps XDocument) using GetXml()... manipulate the XML directly, push it back in with UpdateXml() and Save.

like image 33
Dominic Cronin Avatar answered Mar 29 '23 17:03

Dominic Cronin