Search code examples
c#dynamics-crmdataversepower-platformdatabase-metadata

Retrieve entities and other objects from a solution / solutioncomponents in order to delete them, using Dataverse client Sdk


I need to delete all objects in a solution (ideally in a batch). I have already found several ways to get all their IDs by retrieving the solutioncomponent table. But it seems that to delete them I also need their LogicalName or Name, depending on their type, and then I have to use different delete methods for each type.

I got it to work with a lot of code, loops and case distinctions. Is there a more elegant or simpler way?

I'll post my own code later as an answer, but it's long and I don't like it very much, and it's hard to decide which way to go.

Is RetrieveMetadataChanges an option? It seems complicated and I haven't tried it yet.


Solution

  • Here is my working code which handles entities and optionsets:

    private static async Task DeleteSolutionComponents(Guid solutionId)
    {
        using var context = new ServiceContext(svc);
    
        var entityQuery = from c in context.SolutionComponentSet
                          join e in context.Entity_EntSet
                          on c.ObjectId equals e.EntityId
                          where c.SolutionId.Id == solutionId
                          select e.LogicalName1;
    
        foreach (string logicalName in entityQuery)
        {
            DeleteEntityRequest deleteEntityRequest = new() { LogicalName = logicalName };
            var deleteEntityResponse = (DeleteEntityResponse)await svc.ExecuteAsync(deleteEntityRequest);
        }
    
        var optionSetQuery = from c in context.SolutionComponentSet
                             where c.SolutionId.Id == solutionId && c.ComponentType == componenttype.OptionSet
                             select c.ObjectId;
    
        foreach (Guid objectId in optionSetQuery)
        {
            RetrieveOptionSetRequest retrieveOptionSetRequest = new() { MetadataId = objectId };
            string optionSetName = ((RetrieveOptionSetResponse)await svc.ExecuteAsync(retrieveOptionSetRequest)).OptionSetMetadata.Name;
    
            DeleteOptionSetRequest deleteOptionSetRequest = new() { Name = optionSetName };
            var deleteOptionSetResponse = (DeleteOptionSetResponse)await svc.ExecuteAsync(deleteOptionSetRequest);
        }
    }
    

    I used CrmSvcUtil.exe to generate early bound classes, which also enabled that nice linq join (bad: non-async) for entities. However, I couldn't get it to work for optionsets. CrmSvcUtil.exe skipped them and I think it's because they don't support RetrieveMultiple. Is there a better way? Is it possible to handle deleting different component types in one loop? I just wanted to share my code, but I am hoping for a better answer.

    (At least the deletions could be executed together in an ExecuteTransactionRequest, this is not yet included in the above code).