Nick
Nick

Reputation: 870

Linq Query in a (Pre Delete Operation) Plugin

I have a plugin that fires on Pre Delete Operation. Inside the Plugin I need to run a linq query to get a list of guids for another entity related to the entity where the plugin fired on.

When using my query in this plugin it does NOT get back any data but when I run the same query from a post update operation plugin it returns data.

I am NOT sure if the issue is related to the pre delete operation or something else. Please Note that EntityA is the entity that the plugin fires on.

Here is my code and I do really appreciate your help:

using (var serviceContext = new OrganizationServiceContext(service))
            {
                Entity bEntity = new Entity("EntityB");
                serviceContext.AddObject(bEntity);

           var qTr = from n in serviceContext.CreateQuery<EntityB>()
           where n.field.Id.Equals(new Guid(EntityAGuid.ToString())) 
                          select n.EntityBguid;

                foreach (var trGuid in qTr)
                {
                   service.Delete("EntityB", (Guid)trGuid);
                }
           }

Upvotes: 3

Views: 1683

Answers (4)

Nick
Nick

Reputation: 870

If you want to write a plugin that needs to read children of a record being deleted – this must be done in the Pre Validation stage.

Why is that?

For 1:N relations with Delete Behavior: Remove Link, the lookup to the parent being deleted is set to null somewhere between stage 10 (Pre Validation) and 20 (Pre Operation), but inside the transaction of the primary record deletion.

So if trying to retrieve the children in any stage after Pre Validation you will not get any results, as they all have a not-yet-committed update transaction where the relation is nulled.

Why on earth should I care?

You might agree with me that the constraints regarding cascade behavior on relationships do not quite fulfill the needs that are quite common when creating manual N:N relations.

https://community.dynamics.com/crm/b/cinterosab_crmblog/archive/2012/10/02/crm-plugins-retrieve-children-during-delete.aspx

Upvotes: 2

Nick
Nick

Reputation: 870

If you are running a plugin on the pre-operation event of the Delete message, one thing to note is that by that time CRM has already disassociated the record in context with any child records. Therefore if you need to query for any child records relating to that record, nothing will return from your query.

A way around this would be to register your plugin in the pre-validation event. http://mscrmdev.blogspot.ca/2012/02/pre-delete-plugin-gotcha.html

Upvotes: 0

LameCoder
LameCoder

Reputation: 1297

So this isn't ideal but this is working for me. You need two plugins. A Pre-Validation and either a Pre-Operation or Post-Operation (the choice is yours).

It's important to note that you need to use ParentContext in the Pre-Operation or Post-Operation plugin.

More info on SharedVariables found on this blog: http://thomasthankachan.com/2011/08/12/pass-data-between-plug-ins-using-sharedvariables/

Do as follows:

protected void PreValidate(LocalPluginContext localContext)
{
    IPluginExecutionContext context = localContext.PluginExecutionContext;                 
    IOrganizationService service = localContext.OrganizationService;

    using (var serviceContext = new OrganizationServiceContext(service))
    {
        Entity bEntity = new Entity("EntityB");
        serviceContext.AddObject(bEntity);

        var qTr = from n in serviceContext.CreateQuery<EntityB>()
        where n.field.Id.Equals(new Guid(EntityAGuid.ToString())) 
                      select n.EntityBguid;

        List<Guid> guids = new List<Guid>();
        foreach (var trGuid in qTr)
        {
            guids.Add((Guid)trGuid);
        }

        context.SharedVariables.Add("GuidsToDelete", guids);
    }
}

protected void PostOperation(LocalPluginContext localContext)
{
    object o;
    if(localContext.PluginExecutionContext.ParentContext.SharedVariables.TryGetValue("GuidsToDelete", out o))
    {
        List<Guid> guids = (List<Guid>)o;
        foreach(var g in guids)
        {
            localContext.OrganizationService.Delete("EntityB", (Guid)trGuid);
        }
    }
}

Upvotes: 0

Daryl
Daryl

Reputation: 18895

I'm guessing you aren't creating your IOrganisationalService from the plugin context but creating an OrganizationServiceProxy. This is bad for two reasons.

  1. You're already on the server and making another WCF call to the same server.
  2. This external call is outside of the database transaction. This is why the entity doesn't exist.

Upvotes: 0

Related Questions