I am using Service Manager/System Center 2012, Service Pack 1. (Version 7.5.2905.0
I am attempting to do something that should be simple, but there appears to be ZERO documentation on how to actually do the queries. So, I have a User object (EnterpriseManagementObject for that user), and I want to query service manager for all incidents that that user is the affected user.
Code is: (From an example I found)
strIncidentSearchCriteria =
String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAffectedUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/UserName$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>" + user.FullName + @"</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</Criteria>");
EnterpriseManagementObjectCriteria emocWorkitem = new EnterpriseManagementObjectCriteria(incidentSearchCriteria, mpc, mp, emg);
This throws an exception:
The provided path ($Context/Path[Relationship='WorkItem!System.WorkItemAffectedUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/UserName$) was not valid.
Parameter name: pathReference
I'm pretty sure that the Property field is wrong, but there seems to be no documentation on how you could create the XML, or how to specify the Property, or anything.
The code around this works correctly if I change the search to:
//strIncidentSearchCriteria = String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">" +
// "<Expression>" +
// "<SimpleExpression>" +
// "<ValueExpressionLeft>" +
// "<Property>$Context/Property[Type='System.WorkItem.Incident']/Status$</Property>" +
// "</ValueExpressionLeft>" +
// "<Operator>NotEqual</Operator>" +
// "<ValueExpressionRight>" +
// "<Value>" + new Guid("2b8830b6-59f0-f574-9c2a-f4b4682f1681") + "</Value>" + // Resolved
// //Closed:"<Value>" + new Guid("bd0ae7c4-3315-2eb3-7933-82dfc482dbaf") + "</Value>" +
// "</ValueExpressionRight>" +
// "</SimpleExpression>" +
// "</Expression>" +
// "</Criteria>");
(Of course, not commented out)
Also, another issue: If I do the query above and return all the matching incidents that are resolved - It runs out of memory before it is able to enumerate - apparently, it was written so it pulls everything that matches into a list or something and then you enumerate that - instead of pulling more data as needed. Any way I can pull everything? (My original method was to pull everything and then filter it myself - this was a one-off and I could live with it taking an hour if needed. (However, I will also need this query for a long term project, so I'm really needing to know how to query all incidents that affect a given user, and then also all that the assigned user is X, etc. Where do you learn this stuff??)
Update:
This query, fails, how to I make it work. (This is the thing that I'm ultimately trying to get working)
<Criteria xmlns="http://Microsoft.EnterpriseManagement.Core.Criteria/">
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>NotEqual</Operator>
<ValueExpressionRight>
<Value>2b8830b6-59f0-f574-9c2a-f4b4682f1681</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>NotEqual</Operator>
<ValueExpressionRight>
<Value>bd0ae7c4-3315-2eb3-7933-82dfc482dbaf</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/DisplayName$</Property>
</ValueExpressionLeft>
<Operator>Like</Operator>
<ValueExpressionRight>
<Value>%Bill%</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</And>
</Expression>
</Criteria>
======= Update and solution ========
Figured it out, you have to tell it where the Incident type is located, so this query works:
<Criteria xmlns="http://Microsoft.EnterpriseManagement.Core.Criteria/">
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>NotEqual</Operator>
<ValueExpressionRight>
<Value>2b8830b6-59f0-f574-9c2a-f4b4682f1681</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>NotEqual</Operator>
<ValueExpressionRight>
<Value>bd0ae7c4-3315-2eb3-7933-82dfc482dbaf</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/DisplayName$</Property>
</ValueExpressionLeft>
<Operator>Like</Operator>
<ValueExpressionRight>
<Value>%Bill%</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</Expression>
</And>
</Expression>
</Criteria>
I recommend you to learn about Type Projections... ¿Why? Because Type Projections are like Views in Service Manager. Your commented criteria works perfect because you're only using a simple EnterpriseManagementObject
and his properties are available in System.WorkItem.Incident
class which in turn lives into System.WorkItem.Incident.Library
management pack. The exception that your code is throwing is correct because he can't find that path inside the basic definition of an incident class.
The Solution? Type Projections.
This path: $Context/Path[Relationship='WorkItem!System.WorkItemAffectedUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/UserName$
belongs to a relationship between the incident and the affected user.
So if you run this query you can find the name of this Type Projection:
SELECT
LT.ElementName,
LT.LTValue,
LT.MPElementId,
MP.MPName,
MP.MPFriendlyName,
MP.MPKeyToken,
MP.MPVersion
FROM
LocalizedText LT
INNER JOIN
ManagementPack MP ON LT.ManagementPackId = MP.ManagementPackId
WHERE
LT.ElementName like '%Incident.Projection%'
AND
LT.LanguageCode like '%ENU%'
You'll find that the name of the Type Projection that you´re searching is System.WorkItem.Incident.ProjectionType
and he lives in ServiceManager.IncidentManagement.Library
management pack.
Now is time to go to VS. Now we have to change the object that we're using (EnterpriseManagementObject
) for EnterpriseManagementObjectProjection
so:
string strCriteria =
String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAffectedUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/UserName$</Property>
</ValueExpressionLeft>
<Operator>Like</Operator>
<ValueExpressionRight>
<Value>%" + userName + @"%</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</Criteria>");
ManagementPack workItemMp = emg.GetManagementPack("System.WorkItem.Incident.Library", "31bf3856ad364e35", new Version("7.5.3079.0")); // Incident MP
ManagementPack projMp = emg.GetManagementPack("ServiceManager.IncidentManagement.Library", "31bf3856ad364e35", new Version("7.5.3079.0")); // <-- MP where Type Projection lives
ManagementPackTypeProjection workItemRelConfigProj = emg.EntityTypes.GetTypeProjection("System.WorkItem.Incident.ProjectionType", projMp); // <-- Type Projection Name
ObjectProjectionCriteria projCriteria = new ObjectProjectionCriteria(strCriteria, workItemRelConfigProj, projMp, emg);
IObjectProjectionReader<EnterpriseManagementObject> reader = emg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(projCriteria, ObjectQueryOptions.Default);
if (reader != null && reader.Count > 0)
{
foreach (EnterpriseManagementObjectProjection obj in reader)
{
//TO DO
}
}
So now your path will works perfectly and this will return the objects that you want :-). I hope this help.
Cheers from Chile!