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