4

I have this code that runs in a real time workflow on record creation. It basically determines on which entity it's running on, tries to get the "related to field", which can change from entity to another, then see if the related record is an account, if so, update some of the account's attributes.

public override void ExecuteWorkflowLogic(XrmObjects xrmObjects)
{
    using (XrmServiceContext ctx = new XrmServiceContext(xrmObjects.Service))
    {
        var target = xrmObjects.WorkflowContext.InputParameters["Target"] as Entity;
        Xrm.Account account = null;
        var regardingFieldName = string.Empty;

        var logicalName = string.Empty;
        var primaryKeyName = string.Empty;

        switch (target.LogicalName)
        {
            case Xrm.Task.EntityLogicalName:
            case Xrm.Email.EntityLogicalName:
            case Xrm.PhoneCall.EntityLogicalName:
            case Xrm.Letter.EntityLogicalName:
            case Xrm.Appointment.EntityLogicalName:
            case Xrm.Fax.EntityLogicalName:
                regardingFieldName = "regardingobjectid";
                logicalName = Xrm.ActivityPointer.EntityLogicalName;
                primaryKeyName = "activityid";
                break;
            case Xrm.Annotation.EntityLogicalName:
                logicalName = Xrm.Annotation.EntityLogicalName;
                regardingFieldName = "objectid";
                primaryKeyName = "annotationid";
                break;
            case Xrm.Opportunity.EntityLogicalName:
                regardingFieldName = "customerid";
                logicalName = Xrm.Opportunity.EntityLogicalName;
                primaryKeyName = "opportunityid";
                break;
            case Xrm.Post.EntityLogicalName:
                regardingFieldName = "regardingobjectid";
                logicalName = Xrm.Post.EntityLogicalName;
                primaryKeyName = "postid";
                break;
         }


         var activity = (from a in ctx.CreateQuery(logicalName)
                                where a[regardingFieldName] != null && (Guid)a[primaryKeyName] == target.Id
                                select a).FirstOrDefault();

         var ec = (EntityReference)activity[regardingFieldName];

         if (ec == null)
             return;

         //if regarding isn't an account...
         if (ec.LogicalName != Xrm.Account.EntityLogicalName)
             return;

         account = ctx.AccountSet.SingleOrDefault(x => x.Id == ec.Id);

         if (account == null)
             return;

         account.new_last_activity_created_by = (EntityReference)target["createdby"];
         account.new_last_activity_date = (DateTime)target["createdon"];
         account.new_last_activity_type = GetActivityType(target); //returns an optionset based on entity logical name....
         account.new_last_activity_entity_logicalname = target.LogicalName;

         if (!ctx.IsAttached(account))
              ctx.Attach(account);

         ctx.UpdateObject(account);
         ctx.SaveChanges();
    }
}

I want it to run in a real time workflow, because the changes are going to be instant and also, because the user created the entity above may not have the right to update the account, so a real time workflow allows me to do the update as another user (workflow owner) that has the rights to do so.

The problem is when it's for an activity entity (the first big block in the switch statement), the record looks like it has no been committed to the database and there's no way for me to fetch it and look further into it (activity ends up null)

If I look for target's GUID in ActivityPointerBase or TaskBase, EmailBase, etc. I am not seeing it anywhere during the execution of this workflow (which happens after a record is created I assume)

If I run this in an async workflow, it works for all entities.

In real time mode, it only works for opportunities, posts and annotations. I am creating the activities from the social feed menu in my tests.

The code above runs within a method in a class that extends BaseWorkflowStep:

public abstract class BaseWorkflowStep : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
        var xrmObjects = new XrmObjects();

        var serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
        xrmObjects.CodeActivityContext = context;
        xrmObjects.TracingService = context.GetExtension<ITracingService>();
        xrmObjects.WorkflowContext = context.GetExtension<IWorkflowContext>();
        xrmObjects.Service = serviceFactory.CreateOrganizationService(xrmObjects.WorkflowContext.UserId);

        ExecuteWorkflowLogic(xrmObjects);
    }

    public virtual void ExecuteWorkflowLogic(XrmObjects xrmObjects)
    {
        throw new NotImplementedException();
    }
}

What's happening here ?

Francis Ducharme
  • 4,848
  • 6
  • 43
  • 81

1 Answers1

0

This is probably too old now, but if you're using a real-time Workflow (RTWF), then at the time your WF is running the record wouldn't be committed yet. This is in part because if your RTWF fails, the failure will cancel the creation of the primary record. So the primary record and your code results are a part of the same DB transaction. That's why async works too, since those operations occur in separate DB transactions. Instead of querying for the data, instead use the images that are passed in the Context. For example, if this were occurring after the creation of a record, you might use the "PostBusinessEntity" within the PostEntityImage collection.

mppowe
  • 215
  • 1
  • 11