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();
}
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With