November Happy Hour will be moved to Thursday December 5th.

Manoj Kumawat
Feb 27, 2023
  1635
(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
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog