Home > Object Model, Share Point, SharePoint 2010 > SharePoint: How to Delete a List Field/Column programmatically

SharePoint: How to Delete a List Field/Column programmatically

    Sometimes I need to remove a list field, which is not in use anymore. To remove the field we need just to call SPField.Delete method. However, there are situations when the field cannot be deleted due to some conditions, for example, when the field is read-only and etc. Because of that you might get such exceptions as

"The field cannot be deleted because it is a read only field in the list."
"The field cannot be deleted because it is a sealed field in the list."
"The field cannot be deleted because it is a hidden field in the list."

and other. So, let’s consider how these difficulties can be overcome (if it’s possible at all).


Inside the SPField.Delete method

The SPField.Delete does nothing except calling the Delete method of the SPFieldCollection class. The listing below demonstrates the short version of the SPFieldCollection.Delete:

public void Delete(string internalFieldName)
{
    SPField fld = ... // get the field from the current collection
    ...	

    if (!fld.CanBeDeleted)
        ... // throw an eception

    SPFieldLookup lookup = fld as SPFieldLookup;
    if (((lookup != null) && !lookup.IsDependentLookup) && (lookup.GetDependentLookupInternalNames().ToArray().Length != 0))
        ... // throw an eception     

    ... // delete the field
}

Where the CanBeDeleted property of the field defined as the following:

public bool CanBeDeleted
{
    get
    {
        if (this.AllowDeletion.HasValue)
            return this.AllowDeletion.Value;
        return (!this.FromBaseType && !this.Sealed);
    }
}

*Note: this code is true for both SharePoint 2007 and SharePoint 2010.

As we can see, deleting a list field, SharePoint explicitly analyzes such properties of the field as AllowDeletion, Sealed and FromBaseType. Additionally, experiments show that the ReadOnlyField and Hidden properties are being examined as well (likely it happens somewhere in the unmanaged SharePoint modules).


Workaround

An obvious workaround is, before calling SPField.Delete, change the above properties so that the field would be allowed for deletion. So, taking that into account, I implemented the following method(s) to delete list fields:

public static bool RemoveField(SPField spField)
{
    if (spField == null)
    {
        WriteErrorToLog("spField is null! Please, provide a valid one");
        return false;
    }

    bool res = false;
    try
    {
        // check if it's a ReadOnly field.
        // if so, reset it
        if (spField.ReadOnlyField)
        {
            spField.ReadOnlyField = false;
            spField.Update();
        }

        // check if it's a Hidden field.
        // if so, reset it
        if (spField.Hidden)
        {
            spField.Hidden = false;
            spField.Update();
        }

        // check if the AllowDeletion property is set to false.
        // if so, reset it to true
        if (spField.AllowDeletion == null || !spField.AllowDeletion.Value)
        {
            spField.AllowDeletion = true;
            spField.Update();
        }

        // If the AllowDeletion property is set,
        // the Sealed property seems not to be examined at all.
        // So the following piece of code is commented.
        /*if(spField.Sealed)
        {
            spField.Sealed = false;
            spField.Update();
        }*/

        // If the AllowDeletion property is set,
        // the FromBaseType property seems not to be examined at all.
        // So the following piece of code is commented.
        /*if(spField.FromBaseType)
        {
            spField.FromBaseType = false;
            spField.Update();
        }*/

        // finally, remove the field
        spField.Delete();
        spField.ParentList.Update();

        res = true;
    }
    catch (Exception ex)
    {
        WriteErrorToLog(ex.Message);
    }

    return res;
}

public static bool RemoveField(SPList spList, string displayNameOrInternalNameOrStaticName)
{
    SPField spField = GetFieldByName(spList, displayNameOrInternalNameOrStaticName);
    if(spField == null)
    {
        WriteErrorToLog(string.Format("Couldn't find field {0}!", displayNameOrInternalNameOrStaticName));
        return false;
    }

    return RemoveField(spField);
}

public static void WriteErrorToLog(string errorMsg)
{
    // write error into log
}

*Note: the GetFieldByName method is described here – Getting SPField with no exceptions to be thrown.

According to the code of the CanBeDeleted, the Sealed and FromBaseType properties are not being examined at all while the AllowDeletion is set. Thus the dealing with them is commented, but retained just in case.

Below is a sample of use:

SPSecurity.RunWithElevatedPrivileges(delegate
{
    using (SPSite spSite = new SPSite("some site url"))
        using (SPWeb spWeb = spSite.OpenWeb())
        {
            SPList spList = GetListByUrl(spWeb, "Lists/Products");
            RemoveField(spList, "product name");
        }
});

*Note: the GetListByUrl method is described here – Getting SPList with no exceptions to be thrown.

The RemoveField method isn’t a panacea. For example, you still will have problems if the field going to be deleted is a part of a multiple column lookup.

Be very careful when deleting fields, because it can lead to severe issues in your SharePoint applications. If you are uncertain, don’t delete anything, especially if it concerns a live application on a production server. Remember that you are always able to just make the field hidden instead.

 
  1. swarnim
    August 7th, 2012 at 08:58 | #1

    //Try out this snippet. It will help u

    SPList lst = web.Lists["swarnim_list"];
    lst.Fields.Delete(“Date of birth”);
    lst.Update();

  2. August 7th, 2012 at 09:28 | #2

    @swarnim
    Hello!
    You seemed not to read the post thoroughly. SPFieldCollection.Delete couldn’t help anybody if the target field is read-only, hidden or sealed. Also, there is no difference between SPField.Delete and SPFieldCollection.Delete, because the last one is called from the first one.

  3. Jess Gordon
    October 30th, 2013 at 14:44 | #3

    Hi: I found your solution above – thanks much for taking the time to share.
    I have a problem. I have run across code snippets of this sort for many purposes and I can even follow the logic flow. What I cannot figure out is HOW to use them! I mean, exactly where is this code snippet run?What tool do I need to use to load the snippet – Visual Studio? Would I need to create a new project in VS and paste the code into it in order to run it?
    Since no one who publishes these code examples mentions anything about how to use them, I have the feeling that I am missing something huge, but just what it is…
    Thanks for any time you might afford to explain this to me.
    Jess

  4. Admin
    October 30th, 2013 at 15:53 | #4

    @Jess Gordon
    Hello!
    You can create a simple console application in VS, add reference to (at least) Microsoft.SharePoint.dll and then put something like this:

    SPSecurity.RunWithElevatedPrivileges(delegate
    {
        using (SPSite spSite = new SPSite("some site url"))
            using (SPWeb spWeb = spSite.OpenWeb())
            {
                SPList spList = GetListByUrl(spWeb, "Lists/Products");
                RemoveField(spList, "product name");
            }
    });
    

    Or you can create a SharePoint solution in VS (or use existent one) and add a Feature, then add an Event Receiver and put the above code snippet within the FeatureActivated event handler. Once you deploy and activate the Feature the code will be performed.

  1. No trackbacks yet.