locked
Get Activity Parent WorkItem Assigned To User RRS feed

  • Question

  • Hi all

    I try to get the Affected User of a parent Service Request starting from a Manual Activity. I have an IDataItem representing the selected activity.

    From there I am able to get the parent workitem by using the "ParentWorkItem" component.

    DataItemCollection parentWorkItems = (DataItemCollection)dataitemActivity["ParentWorkItem"];
    IDataItem parentWorkItem = parentWorkItems[0] as IDataItem;

    However I am kind of stuck here. I can do parent["Title"] which will return the correct title but I can't use any components like "AssignedTo". This gives me a propertyName error.

    What am I missing? Thanks for your help!



    Blog: http://scsmlab.com  Twitter: @scsmlab

    Monday, May 11, 2015 4:09 PM

Answers

  • If you can't change the form's target type projection, then use ConsoleContextHelper.Instance.FetchAndMergeSubProjection to augment the existing projection.

    Create your own custom type projection with the same seed as your form's type projection (for instance, System.WorkItem.Activity.ManualActivity or, more generically, System.WorkItem.Activity).

    Add all of the components to this type projection that you'll need in your task. Use UNIQUE aliases for each component.. like "MyParentWorkITem", "MyAssignedTo", etc etc. Do not duplicate an alias in your type projection that already exists in the form's type projection (You'll experience incorrect behavior that is difficult to debug).

    Next, use ConsoleContextHelper.Instance.FetchAndMergeSubProjection to merge your custom type projection into the existing form projection.

    Also, notice where I'm using "Type projection" and "projection". They're different for a reason :) Type projections are those things defined in management packs. Projections are blocks of data from the database which are organized like their type projection.

    Beware of the following caveats using this method: It is not thread safe. In other words, if you have a separate thread working on your projection when you fetchandmerge, the projection will first get the new aliases (fetch) and _then_ get the data (merge). These two do not happen in a single locking transaction. This holds true for the data context's PropertyChanged event handler as well. For every fetchandmerge, the PropertyChanged event will fire twice. Once when the alias is added and again when the data is loaded into the alias. If you're not doing any threading or PropertyChanged event handling, then don't worry about it; FetchAndMergeSubProjection will block its calling thread like any other method (in other words, it won't return until the entire fetchandmerge procedure is finished).

    Second caveat: There's a performance impact using this method. It's making another call to the CMDB and bringing back data. So use it sparingly if possible.

    After the fetch and merge is finished, you can use your custom aliases just like you would if the form contained it from the start.


    Monday, May 11, 2015 8:43 PM

All replies

  • Which one do you need? AffectedUser, AssignedTo, or both?

    Are you sure the AssignedToUser and/or AffectedUser component is in your type projection for the ParentWorkItem? If so, you have to use its Alias.

    Your type projection should look roughly like this (MP references not-withstanding, of course):

    <TypeProjection ... Type="System.WorkItem.Activity.ManualActivity">
      <Component Path="$Context/Path[Relationship='System.WorkItemContainsActivity' SeedRole='Target']$" Alias="ParentWorkItem">
        <Component Path="$Context/Path[Relationship='System.WorkItemAssignedToUser']$" Alias="ParentWorkItemAssignedToUser" />
        <Component Path="$Context/Path[Relationship='System.WorkItemAffectedUser']$" Alias="ParentWorkItemAffectedUser" />
      </Component>
    </TypeProjection>

    If this is the case, parentWorkItem["ParentWorkItemAssignedToUser"] and parentWorkItem["ParentWorkItemAffectedUser"] will work.

    Monday, May 11, 2015 4:47 PM
  • Aaron - thanks for your prompt reply! Actually the AssignedTo user was just an example. What I would like to do is to start from an activity and get a config item which is related through several relationships to this activity (e.g. activity - parent service request - assigned user - related config item).

    I was thinking of just getting each object as IDataItem through appropriate component like this:

    IDataItem serviceRequest = activity["ParentWorkItem"] as IDataItem;
    IDataItem user = serviceRequest["AssignedTo"] as IDataItem;

    Is this even possible or would I have to use EMG instead of IDataItem? I understand that if we had a custom typeprojection which includes the nested components to get the final object, I could just use the appropriate alias. I actually did not think about this. Thought it would be easier to just go from object to object until I reach the final destination :-)

    What would be the preferred method? And if using a custom typeprojection, how can I make sure that this one is used when starting all this as a task from an activity form?

    Thanks a lot for your help!


    Blog: http://scsmlab.com  Twitter: @scsmlab

    Monday, May 11, 2015 8:25 PM
  • If you can't change the form's target type projection, then use ConsoleContextHelper.Instance.FetchAndMergeSubProjection to augment the existing projection.

    Create your own custom type projection with the same seed as your form's type projection (for instance, System.WorkItem.Activity.ManualActivity or, more generically, System.WorkItem.Activity).

    Add all of the components to this type projection that you'll need in your task. Use UNIQUE aliases for each component.. like "MyParentWorkITem", "MyAssignedTo", etc etc. Do not duplicate an alias in your type projection that already exists in the form's type projection (You'll experience incorrect behavior that is difficult to debug).

    Next, use ConsoleContextHelper.Instance.FetchAndMergeSubProjection to merge your custom type projection into the existing form projection.

    Also, notice where I'm using "Type projection" and "projection". They're different for a reason :) Type projections are those things defined in management packs. Projections are blocks of data from the database which are organized like their type projection.

    Beware of the following caveats using this method: It is not thread safe. In other words, if you have a separate thread working on your projection when you fetchandmerge, the projection will first get the new aliases (fetch) and _then_ get the data (merge). These two do not happen in a single locking transaction. This holds true for the data context's PropertyChanged event handler as well. For every fetchandmerge, the PropertyChanged event will fire twice. Once when the alias is added and again when the data is loaded into the alias. If you're not doing any threading or PropertyChanged event handling, then don't worry about it; FetchAndMergeSubProjection will block its calling thread like any other method (in other words, it won't return until the entire fetchandmerge procedure is finished).

    Second caveat: There's a performance impact using this method. It's making another call to the CMDB and bringing back data. So use it sparingly if possible.

    After the fetch and merge is finished, you can use your custom aliases just like you would if the form contained it from the start.


    Monday, May 11, 2015 8:43 PM
  • Awesome! Thanks for this - as always - very detailed explanation. I will give it a try and let you know how it worked!


    Blog: http://scsmlab.com  Twitter: @scsmlab

    Monday, May 11, 2015 9:10 PM
  • Aaron - I was able to test this and it works fine. Thanks!

    However, one follow up question about ConsoleContextHelper.Instance.FetchAndMergeSubProjectionis there a way to somehow merge subprojections without knowing their guid?

    I am thinking about a general task which targets Service Requests. However the task could be run from a custom child SR class which inherits System.WorkItem.ServiceRequest. Since I need to specify the guid of the custom child class TP for FetchAndMergeSubProjection, the task would not work with a newly created other chlid class.

    The only way I can think of to somehow generalize is always getting instance class followed by getting all TypeProjections for the appropriate class and randomly pick one to merge right? Or does it make sens to merge all projections found? But this could probably lead to a performance issue right?

    Thanks for your time!

    Stefan


    Blog: http://scsmlab.com  Twitter: @scsmlab

    Monday, May 18, 2015 9:51 AM
  • I'm glad I could help :)

    If you're always working with classes that inherit from ServiceRequest, you can use the same ServiceRequest seeded type projection for any fetchandmerge on an instance that inherits from service request.

    If, however, you have unique relationships defined for those inherited classes that then require type projections whose seeds are those inherited classes, then yeah, you'll need your own way of identifying which type projection should be merged. (and this is assuming I understand your requirements :) )

    I'm not sure where you were going with the "randomly pick one" approach. If the randomly chosen type projection doesn't contain the components you want, then your task won't work.

    There are a couple approaches you could take. You could build a custom administration setting that lets you associate a specific type projection to a specific class. Or, (and this is a little quicker), you could give your custom type projections a specific naming scheme that matches with the class that it belongs to. As long as you follow that naming scheme, your task can always pick the correct type projection for that class.

    Monday, May 18, 2015 1:46 PM