TCS Tools: Expressions Syntax (CRMContext object and Sequence function)

By | May 1, 2017

CRMContext is a special object that is available to you in the code expressions, and that provides some core properties / methods you can use to work with Dynamics.

Here is an example of a code expression that’s using CRMContext:

CRMContext.Target[“name”] = “First Account”;

This expression is going to set “name” parameter of the target record to “First Account”.

Let’s see what’s available there:

1. CRMContext.Target

For the Create/Update/Delete/Retrieve expressions, this is the actual entity record for which your expression is running. If you are familiar with plugins development, it’s what you would get in the plugin if you accessed context.InputParameters[“Target”]

CRMContext.Target[“name”] = “Test Account”;

For the RetrieveMultiple expressions, this is, actually, an EntityCollection. Which is the same as context.InputParameters[“BusinessEntityCollection”] in the plugins.

 

foreach(a in CRMContext.Target.Entities)
{
 a[“name”] = “Test”;
}

2. CRMContext.PreImage

For the Update/Delete expressions, this is how the entity looked like before the operation started.

if(CRMContext.PreImage[“name”] == CRMContext.Target[“name”]){

}

 

 

3. CRMContext.UserId

This is GUID of the user performing the operation

 

4. CRMContext.CreateRecord(string entityName)

You can use this function to create a new entity record:

newRecord = CRMContext.CreateRecord(“account”);

 

5. CRMContext.SaveRecord(Entity entity)

You can use this function to update an entity record. If you used CreateRecord to create that record in the first place, this call will be translated into a “Create” call to the organization service. Otherwise, it’ll be transalted into an “Update” call:

CRMContext.SaveRecord(updatedAccount);

 

6. CRMContext.DeleteRecord(Entity entity)

You can use this function to delete an entity record:

CRMContext.DeleteRecord(account);

 

7. CRMContext.DeleteRecord(Entity entity)

You can use this function to delete an entity record:

CRMContext.DeleteRecord(account);

 

8. CRMContext.LookupRecord(entityName, attributeName, attributeValue)

You can use this function to lookup a record:

contact = CRMContext.LookupRecord(“contact”, “fullname”, “CRM Admin”);

 

9. CRMContext.QueryFetchXml(fetchXml)

You can use QueryFetchXml to run a fetchXml query:

contacts = CRMContext.QueryFetchXml(<YOUR FETCH XML>);
foreach(c in contacts)
{
  …
}

 

12. CRMContext.IsTeamMember(TeamId, UserId)

You can use IsTeamMember function to verify user’s membership in a team:

if(CRMContext.IsTeamMember(teamId, userId))
{
  …
}

13. There is, also, a Sequence(sequenceName, minimumCharacters, leadingCharacters) function that you can use to generate sequential id-s. This function is not in the CRMContext, though:

CRMContext.Target[“name”] = Sequence(“Account”, 5, “*”);

In the example above, “name” attribute of the current entity record will be populated with a new sequential id. That id will be generated for the “Account” sequence (it will be created if it does not exist), it will have at least 5 characters, and, if the number is not big enough, it will use “*” for the leading characters (so, for example, the first time you call it you’ll get *****1 as a result)

27 thoughts on “TCS Tools: Expressions Syntax (CRMContext object and Sequence function)

  1. Firat Vakiliev

    I try to use CRMContext.QueryFetchXml(fetchXml) on Retrieve salesorderdetail with code:

    prop = CRMContext.QueryFetchXml(“”);

    and get error:
    [TreeCatSoftware.Dynamics.TCSTools.Plugins.Expressions: TreeCatSoftware.Dynamics.TCSTools.Plugins.Expressions.ExpressionsPlugin]
    [935942d8-f56d-e711-80d9-005056b37a5c: TreeCatSoftware.Dynamics.TCSTools.Plugins.Expressions.ExpressionsPlugin: Retrieve of salesorderdetail]

    Where I’m wrong? Please clarify or provide any examples.
    Thanks!
    Firat Vakiliev

    Reply
  2. Firat Vakiliev

    My TCS Expression code:
    prop = CRMContext.QueryFetchXml(“”);

    Reply
    1. Alex Shlega Post author

      Hi Firat,

      here is an example (on the retrieve of the account, it will get “firstname” attribute fro a lead and put it into the account name field). QueryFetchXml is trying to run that fetch, so there has to be a fetch in the first place(not an empty string):

      ___________________________________________

      leads = CRMContext.QueryFetchXml("
      <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' top='1' >
      <entity name='lead' >
      <all-attributes/>
      </entity>
      </fetch>");
      foreach(l in leads)
      {
      CRMContext.Target["name"] = l["firstname"];
      }

      Reply
      1. Firat Vakiliev

        Hi Alex!
        How to get PrimaryEntityId (aka IExecutionContext.PrimaryEntityId property)?

        CRMContext.Target[“salesorderdetailid”] does not work 🙁

        Thanks!
        Firat Vakiliev

        Reply
        1. Firat Vakiliev

          Sorry all found. CRMContext.Target is Microsoft.Xrm.Sdk.Entity with all attributes!

          Reply
          1. Alex Shlega Post author

            Hi Firat,

            Yes, that’s exactly it:)

  3. Firat Vakiliev

    Hi Alex!
    My next questions bundle:
    1. How to register new TCS Expression on dynamicpropertyinstance entity? On save raised error! I need to update text field (with json value) in salesorderdetail when any property is changed.
    2. How to update dynamicpropertyinstance object when my json field is changed. In shortly – synch between salesorderdetail and dynamicpropertyinstance.

    May be you can provide any suggestions and/or examples?

    Regards,
    Firat

    PS: Your solution looks like very powerful and usable for me!

    Reply
    1. Alex Shlega Post author

      Hi Firat,

      It seems dynamicpropertyinstance is one of those few entities for which you can’t register a plugin. TCS Expressions are using plugins behind the scene – those plugins will interpret the expressions and run the code.. However, they are still plugins, and they have to be registered (even if the solution does it for you automaticaly).

      If you tried registering a plugin step for DynamicsPropertyInstance in the PluginRegistration tool, you wouldn’t be able to even specify that entity for the plugin step.. In other words, that’s a platform limitation.

      Reply
    2. Xabier

      Hi Firat,

      I also need to update a field of an entity when any property of that entity is changed. Has you found any solution to that?

      Reply
  4. Firat Vakiliev

    Hi Alex!

    I found that the TCS expression (Update) only fires when the is fields changed on form (manually), but it does not run when the entity fields are changed in the workflow or when importing.
    Why is that?

    Regards!
    Firat

    Reply
    1. Alex Shlega Post author

      Hi Firat,

      I am wondering if I need to verify the depth conditions there.. Will take a look tonight, and, if it’s there, will probably republish the solution (will let you know)

      Reply
      1. Firat Vakiliev

        OK. I’m not sleeping and waiting for a new version.

        Reply
        1. Alex Shlega Post author

          Hi Firat,

          here is a link to the “hotfix”

          http://www.itaintboring.com/downloads/v1_0_10/TCSTools_managed.zip

          there will be no ‘depth’ testing there, so, if you actually update the same record from the expression (not if you just set an attribute – that’s fine), this version may start running into infinite loops. Dynamics will prevent infinite recursions, so you’ll see an error message if this happens. Anyway, I will do more testing and publish this version at the regular download location in a few days.

          Reply
          1. Firat Vakiliev

            Hi Alex!

            I’ll try it tonight. In any case, for the time being, I’m afraid to let this decision go into production. We need to test everything well.

            Thanks!

          2. Firat Vakiliev

            Hi Alex!

            At first glance, everything looks great. I checked the work of the Update step through the workflow and the import. I think to try to use the solution in production.

            Thanks,
            Firat

          3. Firat Vakiliev

            Often there are errors associated with looping the plug-in during execution.
            ————————
            This workflow job was canceled because the workflow that started it included an infinite loop. Correct the workflow logic and try again. For information about workflow logic, see Help. If you contact support, please provide the technical details.
            ————————-
            I try to add field name (who is need to me by logic) to “Track Fields for Updates”, but those error appear again. Please clarify how I must use the “Track Fields for Updates”.

            Thanks,
            Firat

            PS: Also, I really need detailed documentation and examples of use.

          4. Alex Shlega Post author

            Hi Firat,

            the purpose of the “track fields for updates” attribute was to ensure those expressions are registered on the specific attributes only. That part has not been implemented so far, though, so that’s why that field is not even on the expression form. Could you post your expression “code” here (or, if you prefer, just send it through the contact page – will get right to me)? That kind of recursion normally happens if you save the same record for which the plugin is running(so, in this case, if you have an expression and you are saving updated record from within the expression, that create a recursion.. technically, you don’t need to save it.. Create/Update expressions will run in the pre-operation, so, if you just update the Target directly, it will be save to the database automatically after that)

          5. Firat Vakiliev

            Hi Alex!

            Yes. In My program I need to change several fields in case of changing one field. In this case, I do not touch the trigger field. However, I thought that “Track Fields for Updates” with my trigger field should prevent recursion.

            Entity: salesorder
            event: update
            Source:
            ————————————–
            pre = CRMContext.PreImage;
            mustApply = pre.Contains(“cp_agreementtemplate”) && entity.Contains(“cp_agreementtemplate”) && pre[“cp_agreementtemplate”].Id.ToString() != entity[“cp_agreementtemplate”].Id.ToString();
            if ( mustApply || pre.Contains(“cp_agreementtemplate”) == false && entity.Contains(“cp_agreementtemplate”)) {
            template = CRMContext.LookupRecord(“cp_agreementtemplate”, “cp_agreementtemplateid”, entity[“cp_agreementtemplate”].Id.ToString());
            entity[“cp_directionofsale”] = template[“cp_directionofsale”];
            entity[“cp_numberofparties”] = template[“cp_numberofparties”];
            entity[“pricelevelid”] = template[“cp_pricelist”];
            entity[“cp_signer”] = template[“cp_signer”];

            entity[“cp_2ndpartysituation_1033”] = template[“cp_2ndpartysituation_1033”];
            entity[“cp_2ndpartysituation_1049”] = template[“cp_2ndpartysituation_1049”];

            entity[“cp_3rdpartysituation_1033”] = null;
            entity[“cp_3rdpartysituation_1049”] = null;
            entity[“cp_3rdpartyentity”] = null;
            entity[“cp_3rdpartyaccount”] = null;
            entity[“cp_3rdpartybank”] = null;
            entity[“cp_3rdpartycontact”] = null;
            entity[“cp_3rdpartyuser”] = null;
            if (template[“cp_numberofparties”].Value == 3) {
            entity[“cp_3rdpartysituation_1033”] = template[“cp_3rdpartysituation_1033”];
            entity[“cp_3rdpartysituation_1049”] = template[“cp_3rdpartysituation_1049”];
            entity[“cp_3rdpartyentity”] = template[“cp_3rdpartyentity”];
            if (template.Contains(“cp_3rdpartyaccount”)) {
            entity[“cp_3rdpartyaccount”] = template[“cp_3rdpartyaccount”];
            }
            if (template.Contains(“cp_3rdpartybank”)) {
            entity[“cp_3rdpartybank”] = template[“cp_3rdpartybank”];
            }
            if (template.Contains(“cp_3rdpartycontact”)) {
            entity[“cp_3rdpartycontact”] = template[“cp_3rdpartycontact”];
            }
            if (template.Contains(“cp_3rdpartyuser”)) {
            entity[“cp_3rdpartyuser”] = template[“cp_3rdpartyuser”];
            }
            }
            }
            ————————————
            Firat

  5. Alex Shlega Post author

    Hi Firat,

    this looks ok to me – you are just adding fields to the “target” record, it’s happening in pre-retrieve.. should not be causing the recursion. Is it possible you have another workflow or plugin that’s responding to the update of those fields somehow (and, maybe, that’s where the recursion happens then?)

    Reply
    1. Firat Vakiliev

      Hi Alex!
      There are no other plugins working together or within this. This is a test program on a clean DB. I’m trying to assess how much the TCS can serve as a quick substitute for classic plugins.

      Firat

      Reply
      1. Alex Shlega Post author

        Hi Firat,

        realistically, I think it’s a “quick fix” solution for when you need to do something quickly and you don’t have a developer around to create a classic plugin.

        Not sure why it would be running into a recursion (I think it’s not, actually, the expression.. not on its own, at least.. Otherwise, it would be doing it every time. There should be something else involved)

        Reply
  6. James

    Hi Alex,

    Another awesome tool thank you! I just have one problem with my fetchXml.

    Using your simple fetchXml above, I got this very simple fetch below working well….

    The problem is I need to refine my fetchXml query with filters, and ideally only pull the attributes (fields) I need rather than all fields in the record. I want my fetch to be based on an Advanced Find output, so it would look more like this:

    However when I run a fetch (using a workflow to run the code), I get this error:

    “Input string was not in a correct format.”

    Any ideas on what the problem might be – I was hoping I can use pretty much any valid Fetch query?

    Many thanks in advance!

    Reply
    1. Alex Shlega Post author

      Hi James,

      you should be able to use pretty much any fetch. Unfortunately, WordPress tends to hide all those xml tags in the comments, but, if you could send me your fetch by email, I’ll have a look ([email protected])

      Reply
        1. James

          Hi all – just to share Alex’s solution to the problem above, I’d wrapped the fetch statement in double quotes, but then also used double-quotes in the fetchxml itself (because that’s how it comes out of advanced find fetchxml in Dynamics). Nested ‘quotes’ are only possible if you use both kinds of quotes to make it clear which is which.

          I replaced all my fetch command ” with ‘ and all was good from there.

          Hope this helps someone. Thanks Alex – you were very helpful as always.

          Reply
          1. Alex Shlega Post author

            Thanks, James! Good to hear it’s working:)

  7. Jeroen

    Hi Alex,
    I wonder how I could use Expressions to retrieve a single value from a related entity.

    For example I’d like to retrieve the city of an account to the contact I’m creating OnCreate. Is that possible?

    Thanks,
    Jeroen

    Reply

Leave a Reply to James Cancel reply

Your email address will not be published. Required fields are marked *