Can someone tell me the easiest way to automatically update all components after some field in schema is updated?
I am thinking of something like event system instead of Core Service tool.
What have you tried? If you're just starting your search then the docs references below are a great start.
Both the TOM.NET and Core Service APIs are available but it shouldn't be about what's easiest. It would be interesting to understand if there some technical or business reason you want to consider using the Event System?
If you have Alchemy installed, there's an app for that, https://www.alchemywebstore.com/plugins/Component-Synchronizer
The risk I see with an Event-driven approach would be
Solution - 1 for your issue:
We have a small command line application we modify as needed to update schema.
We use core services to call GetListXML
on the folder containing the components we want to update:
public XElement GetAllComponents(string folderUri)
{
var filter = new OrganizationalItemItemsFilterData()
{
ItemTypes = new[] { ItemType.Component },
Recursive = true
}
return CORE_SERVICE.GetListXml(folderUri, filter);
}
We then have a simple loop that iterates through each component, checks to see if it uses the schema we want to update, and if so, we call a simple method to update the schema used by the component (both the starting folder and schema we're updating come from the app's config file, but could as easily come from a command line argument.)
We change the code of this method slightly based on what we're trying to update. For instance if we just want to pickup a new field added to the schema we just do a checkout and checkin of the component like so (note we do conduct a simple check to make sure we're only updating 'parent' level components):
public bool UpdateComponentSchema(string componentId)
{
try
{
// get parent level from componentId: tcm:12-234
var parentLevel = componentId.Split(':')[1].Split('-')[0];
var parentLocLevel = string.Format("-{0}-", parentLevel);
var com = CORE_SERVICE.Read(componentId, new ReadOptions()) as ComponentData;
var parentLocation = com.BluePrintInfo.OwningRepository.IdRef;
// check parent location
if (!parentLocation.Contains(parentLocLevel))
return true;
var component = CORE_SERVICE.TryCheckOut(componentId, null) as ComponentData;
if (component != null)
{
try
{
CORE_SERVICE.CheckIn(componentId, null);
}
catch (FaultException fEx)
{
if (!fEx.Message.ToLower().Equals("the item is not checked-out.")) throw fEx;
}
}
}
catch (Exception ex)
{
throw ex;
}
return true;
}
Interestingly, if you update a schema this way the last modified date of the components don't even change.
If we want to update new fields with a specific value we can easily add code to do that after the code that does the component check-out.
We use the same general concept if we need to perform some sort of bulk update/modification of values in components that cannot be handled from within the CME.
We also perform extensive logging around the calls to UpdateComponentSchema so that we have a good record of the successes and failures. If needed we can have someone go back after the fact and touch the failures by hand but in general as long as we've made sure all components are checked in prior to running the app this runs pretty smoothly.
Solution - 2