Having More Fun with Type Projections Using ObjectProjectionCritera

Having More Fun with Type Projections Using ObjectProjectionCritera

  • Comments 1
  • Likes

Hopefully everybody is getting up to speed on type projections.  If you haven’t yet had the fun of reading these posts I suggest doing it!

Using the SDK to Create and Edit Objects and Relationships Using Type Projections

Creating Views That Use Related Property Criteria (Type Projections) : Software Views Example

Creating a View That Shows Users Which Are Primary Users of Computers Which Have a Certain Software Title Installed

Creating Queues and Groups Using Type Projections

Getting Started with Type Projections

More with Type Projections

Getting and Working With Type Projections – Basic

 

Now that you are all familiar with type projections and the power that they can provide let’s take a look at a real world customer example!

First, the customer has a concept of a ‘Company’.  Each company has 0..n sites associated with it.  Each site cannot exist without the company parent.  We would model this like this:

<ClassType ID="Company" Accessibility="Public" Abstract="false" Base="System!System.ConfigItem" Hosted="false" Singleton="false" Extension="false">
  <Property ID="CompanyID" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" />
  <Property ID="Phone" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" />
</ClassType>
<ClassType ID="CompanySite" Accessibility="Public" Abstract="false" Base="System!System.ConfigItem" Hosted="false" Singleton="false" Extension="false">
  <Property ID="CompanySiteID" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" />
  <Property ID="Phone" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" />
</ClassType>

<RelationshipType ID="Sites" Accessibility="Public" Abstract="false" Base="System!System.Membership">
  <Source ID="Source_0f726ba8_caaf_4482_8942_45813659bb23" MinCardinality="0" MaxCardinality="1" Type="Company" />
  <Target ID="Target_cefcf9be_8c79_41e4_a8ab_610febb6c1a9" MinCardinality="0" MaxCardinality="2147483647" Type="CompanySite" />
</RelationshipType>

We can then model the company and its member sites using type projections like this:

<TypeProjection ID="CompanyHasMemberSites" Accessibility="Public" Type="Company">
  <Component Path="$Target/Path[Relationship='Sites']$" Alias="Site" />
</TypeProjection>

Now, let’s say we want to programmatically create some company, a member site, and then retrieve all the sites for that company!

First the code to create a new company and site:

EnterpriseManagementGroup emg = new EnterpriseManagementGroup("localhost");
ManagementPack mpCompany = emg.ManagementPacks.GetManagementPack("CompanyMP", "9396306c2be7fcc4", new Version(1, 0, 0, 0));
ManagementPackClass classCompany = emg.EntityTypes.GetClass("Company", mpCompany);
ManagementPackClass classCompanySite = emg.EntityTypes.GetClass("CompanySite", mpCompany);
ManagementPackRelationship mprSites = emg.EntityTypes.GetRelationshipClass("Sites", mpCompany);
ManagementPackTypeProjection mptpSites = emg.EntityTypes.GetTypeProjection("CompanyHasMemberSites", mpCompany);

CreatableEnterpriseManagementObject cemoCompany = new CreatableEnterpriseManagementObject(emg, classCompany);
string strCompanyID = Guid.NewGuid().ToString();
Console.WriteLine("New Company ID: " + strCompanyID);
cemoCompany[classCompany, "CompanyID"].Value = strCompanyID;

CreatableEnterpriseManagementObject cemoSite = new CreatableEnterpriseManagementObject(emg, classCompanySite);
string strSiteID = Guid.NewGuid().ToString();
Console.WriteLine("New Site ID: " + strSiteID);
cemoSite[classCompanySite, "CompanySiteID"].Value = strSiteID;

CreatableEnterpriseManagementRelationshipObject cemroCompanySite = new CreatableEnterpriseManagementRelationshipObject(emg, mprSites);
cemroCompanySite.SetSource(cemoCompany);
cemroCompanySite.SetTarget(cemoSite);

IncrementalDiscoveryData idd = new IncrementalDiscoveryData();

idd.Add(cemoCompany);
idd.Add(cemoSite);
idd.Add(cemroCompanySite);

idd.Commit(emg);

This should look pretty straightforward for anyone that has been using the SDK for a while.  First we get the management pack elements like the MP itself, the Company and Site classes, the relationship, and the type projection.

Then we use those to create CreatableEnterpriseManagementObjects for the company and the site.  In this case I am just generating a random GUID as the ID.  We’ll then later use that GUID to look up the Company.

Once we have CreatableEnterpriseManagementObjects in memory and a CreatableEnterpriseManagementRelationshipObject we just need to dump those into a IncrementalDiscoveryData bucket and .Commit() it.

Next, let’s look at how to get a Company (and its member sites) using a type projection and ObjectProjectionCriteria.

First, we need to define the XML criteria string.  This is the tricky bit.

string strCompanySitesByCompanyID = String.Format(@"
    <Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
        <Reference Id=""{0}"" Version=""{1}"" PublicKeyToken=""{2}"" Alias=""CompanyMP"" />
        <Expression>
            <SimpleExpression>
              <ValueExpressionLeft>
                <Property>$Target/Property[Type='CompanyMP!Company']/CompanyID$</Property>
              </ValueExpressionLeft>
              <Operator>Equal</Operator>
              <ValueExpressionRight>
                <Value>{3}</Value>
              </ValueExpressionRight>
            </SimpleExpression>
        </Expression>
    </Criteria>",
    mpCompany.Name,
    mpCompany.Version.ToString(),
    mpCompany.KeyToken,
    strCompanyID);

The Reference element at the front simply creates an MP reference to the CompanyMP management pack and sets the alias for that MP to ‘CompanyMP’.  Then we just specify a very simple criteria that says ‘Get all the Company objects (and their member sites) where the CompanyID property = <some passed in value>’.

From there we create an ObjectProjectionCriteria object from the XML string and pass it to GetObjectProjectionReader():

ObjectProjectionCriteria opcCompanySites = new ObjectProjectionCriteria(strCompanySitesByCompanyID, mptpSites, emg);

IObjectProjectionReader<EnterpriseManagementObject> reader = emg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(opcCompanySites, ObjectQueryOptions.Default);

 

From there we can just loop through the returned Company objects (there will be only one in this case since we are querying by the key property) and the member sites:

foreach (EnterpriseManagementObjectProjection emopCompany in reader)
{
    Console.WriteLine("Retrieved Company ID:" + emopCompany.Object.DisplayName);
    foreach (IComposableProjection icpSite in emopCompany[mprSites.Target])
    {
        Console.WriteLine("Site ID: " + icpSite.Object.DisplayName);
    }
}

This is what the output of the Program looks like:

image

Hope that helps!

Source code for the example is attached!

Attachment: Company-ObjectProjectionCriteria Example.zip
Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Travis

    Would you please provide an example with a situation where you must reference multiple classes (say incident and a custom incident). In this case we must add <Reference> tag in the header but I don't know how to do that! When I need to get the IObjectReader, Adding reference at the top of criteria works fine, but when returning IObjectProjectionReader it simply doesn't work (I have tested the same criteria with both).

    Thanks