Wednesday, June 12, 2013

Copy SPField property values without changing Content Type

In a particular project for a client I needed to copy all field properties from document A to document B. However the content type should not be changed. For simplicity I ignore edge cases. For example in case the source and destination content type have different required SPFields.

At first I copied all available fields from source to destination:

foreach (SPField field in sourceItem.Fields)
{
    if (field.ReadOnlyField)
    {
        continue;
    }
    if (destinationListitem.Fields.ContainsField(field.InternalName))
    {
        destinationListitem[field.InternalName] = sourceItem[field.InternalName];
    }
}
destinationListitem.SystemUpdate()

The content type changed. No wonder as the SPField ‘ContentType’ was copied.
Changed code to to ignore SPField ‘ContentType’

IEnumerable<string> ignoreFields = new List<string>()
{
    "ContentType"
};
 
foreach (SPField field in sourceItem.Fields)
{
    if (field.ReadOnlyField)
    {
        continue;
    }
    if (ignoreFields.Contains(field.InternalName, StringComparer.InvariantCultureIgnoreCase))
    {
        continue;
    }
 
    if (destinationListitem.Fields.ContainsField(field.InternalName))
    {
        destinationListitem[field.InternalName] = sourceItem[field.InternalName];
    }
}
destinationListitem.SystemUpdate()

But still content type changed.
It turns out that you need to skip the SPField ‘ContentType’ and ‘MetaInfo’ to make sure the content type of the destination item is not changed.

Final code snippet:

IEnumerable<string> ignoreFields = new List<string>()
{
    "ContentType",
    "MetaInfo"
};
 
foreach (SPField field in sourceItem.Fields)
{
    if (field.ReadOnlyField)
    {
        continue;
    }
    if (ignoreFields.Contains(field.InternalName, StringComparer.InvariantCultureIgnoreCase))
    {
        continue;
    }
 
    if (destinationListitem.Fields.ContainsField(field.InternalName))
    {
        destinationListitem[field.InternalName] = sourceItem[field.InternalName];
    }
}
destinationListitem.SystemUpdate()