maf-soft
maf-soft

Reputation: 2552

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.

Upvotes: 0

Views: 355

Answers (2)

maf-soft
maf-soft

Reputation: 2552

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).

Upvotes: 0

pavan kumar
pavan kumar

Reputation: 36

Deleting a solution component programmatically is very error prone because of the underlying dependencies

  1. Table dependencies
  2. Component Dependencies
  3. Solution dependencies
  4. Internal solution dependencies

So unless there is a pressing need, creating a solution to programmatically delete does not yield good results

Upvotes: 0

Related Questions