Manoj Kumawat
Feb 27, 2023
  1348
(2 votes)

Deleting missing metafields in code programmatically

This blog post will help you in deleting meta fields programatically in catalogue context. We will only delete metafields which are user generated and missing from code (deleted later in the code) but remain in database. 

#1 - get the list of metaclasses (user generated) 

    private readonly Mediachase.MetaDataPlus.Configurator.MetaClassCollection _metaClassCollection;

    _metaClassCollection = Mediachase.MetaDataPlus.Configurator.MetaClass.GetList(CatalogContext.MetaDataContext, true);

    _metaClassCollection.Cast<Mediachase.MetaDataPlus.Configurator.MetaClass>()
                .Where(c => c.IsUser
                && c.MetaFields.Any(x => x.IsUser))

The above collection will fetch meta classes created by the user and any of it's metafields is user generated at least. 

#2 - Getting metafields for class

     metaClass.MetaFields
     .Where(c => c.IsUser && c.OwnerMetaClassIdList.MetaCollectionHasOnly(id))

Above code snippet selects all the meta fields for a metaclass and makes sure it is not fetching any other metafield under a class which comes from relation of the same class (i.e. product > Category > Catalog)
Therefore, It only displays meta fields strictly which are part of the class. I've used an extension method that makes sure each metafiled has only 1 exact same parent as current class. 

 public static bool MetaCollectionHasOnly(this MetaClassIdCollection collection, int classId)
    {
        try
        {
            if (collection != null && collection.Count == 1)
            {
                return collection[0] == classId;
            }

            return false;
        }
        catch
        {
            //we don't want to catch exception in this case.
            return false;
        }
    }

Now it comes to the final step which is most important - Identify missing field from class

Each metaclass is mapped with contentType class you have in your code. Here we need to figure out which class in code is mapped with metaclass in database. Let's understand it easy way -

If I have a base class for all the products in the code as ProductBase with [CatalogContentType] decorator then for MetaClass Product MetaClassToContentTypeMap will fetch ProductBase.

Now the only thing you need to check if the metafield exists in the code as follows - 

private readonly Injected<MetaClassToContentTypeMap> _contentTypeModelRepository;

public string MetaFieldName { get; set; }
private Type ClassType
    {
        get
        {
            return _contentTypeModelRepository.Service.GetContentTypeModel(MetaClassId);
        }
    }

    public bool IsAvailable 
    {
        get
        {
            return ClassType.HasProperty(this.MetaFieldName);
        }
    }

IsAvailable property returns whether the metafield exists in the code or not. 

--------------------------------------------------------------

Update - Deleting what we have detected so far. In my project I had an endpoint which would do it for me. The field you want to delete, send it along with it's parent classId. 

 [HttpPost]
    [Route("metafields/{classId}/delete/{fieldId}", Name = "DeleteMetaField")]
    public JsonResult Delete(int classId, int fieldId)
    {
        var result = false;

        try
        {
            var metaClass = _metaClassCollection.Cast<Mediachase.MetaDataPlus.Configurator.MetaClass>()
                .FirstOrDefault(c => c.Id.Equals(classId));

            if (metaClass != null)
            {
                var metaField = metaClass.MetaFields.FirstOrDefault(c => c.Id.Equals(fieldId));
                metaField.Delete();
            }

            result = true;
        }
        catch (Exception ex)
        {
            Log.Error("Failed to delete" + ex.Message);
            result = false;
        }
        return new JsonResult(result);
    }

And the extension method to delete: 

public static class MetaFieldExtensions
{
    private static readonly MetaDataContext Context = CatalogContext.MetaDataContext;

    public static void Delete(this MetaField metaField)
    {
        if (metaField == null)
        {
            return;
        }
        foreach (var metaClassId in metaField.OwnerMetaClassIdList)
        {
            var cls = Mediachase.MetaDataPlus.Configurator.MetaClass.Load(Context, (int)metaClassId);
            cls.DeleteField(metaField);
        }

        MetaField.Delete(Context, metaField.Id);
    }
}

Hope this helps. 

Feb 27, 2023

Comments

Marcin
Marcin Apr 7, 2023 09:26 AM

@Manoj 

Thanks for the article. In the title I see "Deleting missing metafields in code programmatically", but from the article I only learned how to detect properties that are still in the database, but not in the code. Could you extend the article with more information on how to get rid of such unused properties?

In my case, after using Commerce for a long time, I am dealing with properties that are not used - sometimes they are single, sometimes there are more. I would like them not to be displayed as well as get rid of them from the database to speed up the performance of the products - currently, by handling existing obsolete properties, the products seem to run slower.

Manoj Kumawat
Manoj Kumawat Apr 20, 2023 07:47 AM

Marcin, Just updated it. Hope it helps!

Please login to comment.
Latest blogs
Opti ID overview

Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your use...

K Khan | Jul 26, 2024

Getting Started with Optimizely SaaS using Next.js Starter App - Extend a component - Part 3

This is the final part of our Optimizely SaaS CMS proof-of-concept (POC) blog series. In this post, we'll dive into extending a component within th...

Raghavendra Murthy | Jul 23, 2024 | Syndicated blog

Optimizely Graph – Faceting with Geta Categories

Overview As Optimizely Graph (and Content Cloud SaaS) makes its global debut, it is known that there are going to be some bugs and quirks. One of t...

Eric Markson | Jul 22, 2024 | Syndicated blog

Integration Bynder (DAM) with Optimizely

Bynder is a comprehensive digital asset management (DAM) platform that enables businesses to efficiently manage, store, organize, and share their...

Sanjay Kumar | Jul 22, 2024

Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024