locked
How sgould I be working with Constraints? RRS feed

  • Question

  • I want to get all the Resources for a Resource Group.  Seemed simple enough but after looking around I found code which used fetchxml to extract the constraints.

    Alas the example never showed how to extract the GUIDs from the body of the XML blob which is buried in the object.  Does anyone know how to do this (code follows)?

    These functions return the constraints:

            /// <summary>
            /// Retrieve the Service record (including the constraints linked entity)
            /// </summary>
            /// <remarks>For use in determining the Resource Groups associated with a Service.</remarks>
            private static EntityCollection RetrieveService(IOrganizationService Service, Guid ServiceID)
            {
                string fetchXml =
                    @"<fetch mapping='logical'> 
                    <entity name='service'>
                        <filter type='and'>
                            <condition attribute='serviceid' operator='eq' value='{0}'/>
                        </filter>
                        <link-entity name='resourcespec' from='resourcespecid' to='resourcespecid'>
                            <filter type='and'>
                                <condition attribute='objecttypecode' operator='eq' value='4007'/>
                            </filter>
                            <link-entity name='constraintbasedgroup' from='constraintbasedgroupid' to='groupobjectid'>
                                <attribute name='constraints'/>
                            </link-entity>
                        </link-entity>
                    </entity>
                    </fetch>";
    
                string fetchQuery = string.Format(fetchXml, ServiceID);
                return Service.RetrieveMultiple(new FetchExpression(fetchQuery));
            }
    
            /// <summary>
            /// Retrieve the Resource Group records (including the constraints linked entity)
            /// </summary>
            /// remarks>For use in determining the Resources associated with a Resource Group.</remarks>
            private static EntityCollection RetrieveResourceGroups(IOrganizationService Service, List<Guid> ResourceGroupIdList)
            {
                string conditions = String.Empty;
                foreach (Guid resourcegroupID in ResourceGroupIdList)
                {
                    conditions += string.Format("<condition attribute='resourcegroupid' operator='eq' value='{0}'/>", resourcegroupID);
                }
    
                string fetchXml =
                    @"<fetch mapping='logical'> 
                    <entity name='resourcegroup'>
                        <filter type='and'>
                            <filter type='or'>{0}</filter>
                            <condition attribute='objecttypecode' operator='eq' value='4007'/>
                        </filter>
                        <link-entity name='constraintbasedgroup' from='constraintbasedgroupid' to='resourcegroupid'>
                            <attribute name='constraints'/>
                        </link-entity>
                    </entity>
                    </fetch>";
    
                string fetchQuery = string.Format(fetchXml, conditions);
                return Service.RetrieveMultiple(new FetchExpression(fetchQuery));
            }

    This function should pull it all together:

    public static List<Guid> RetrieveResourcesGUIDs(IOrganizationService Service, Guid ServiceID)
            {
                EntityCollection serviceCollection = CrmCrudHelper.RetrieveService(Service, ServiceID);
    
                List<Guid> resourcegroupGUIDS = new List<Guid>();
                foreach (Entity serviceEntity in serviceCollection.Entities)
                {
                    //AliasedValue alias = (AliasedValue)serviceEntity["constraintbasedgroup2.constraints"];
                    //object constraints = alias.Value;
                    //alias.Value;
                    //guids.Add(entity["constraints"].ToString());
                    resourcegroupGUIDS.Add(new Guid("10c400a5-0aeb-e311-b4ba-d89d6765d360"));
                }
    
                EntityCollection resourcegroupCollection = RetrieveResourceGroups(Service, resourcegroupGUIDS);
    
                List<Guid> resourceGUIDS = new List<Guid>();
                foreach (Entity resourcegroupEntity in resourcegroupCollection.Entities)
                {
                    AliasedValue alias = (AliasedValue)resourcegroupEntity["constraintbasedgroup1.constraints"];
                    object constraints = alias.Value;
                    //guids.Add(entity["constraints"].ToString());
                }
                return resourceGUIDS;
            }

    As you can see I have hard coded the Resource Group ID because I am unsure how to easily retrieve it and I haven't yet attempted to retrieve the list of GUIDs from the second loop.

    The returned XML for the second part of the code is:

    <Constraints>
    <Constraint>
    <Expression>
    <Body>resource["Id"] == {2747588b-43df-e311-80bc-2c59e542862c} || resource["Id"] == {59e6213d-8be1-e311-80bc-2c59e542862c} || resource["Id"] == {3c7ddabe-43df-e311-94b6-80c16e781fe0} || resource["Id"] == {dd06217c-43df-e311-ba5a-d89d67634e04} || resource["Id"] == {25e7038b-43df-e311-ba5a-d89d67634e04} || resource["Id"] == {ca3657be-43df-e311-ba5a-d89d67634e04} || resource["Id"] == {37a6255e-8be1-e311-ba5a-d89d67634e04}</Body>
    <Parameters>
    <Parameter name="resource" />
    </Parameters>
    </Expression>
    </Constraint>
    </Constraints>

    Can I cast this to an object collection or do I have to get dirty with XML?

    Thursday, June 5, 2014 11:18 AM

Answers

  • Had feared that :)

    Wrote an XML function to deal with it and it was fairly painless.

    internal static List<Guid> ExtractIGUIDs(string Xml)
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Xml);
    
                XmlNode node = doc.SelectSingleNode("/Constraints/Constraint/Expression/Body");
                string body = node.InnerText;
    
                string pattern = @"([a-z0-9]{8}[-][a-z0-9]{4}[-][a-z0-9]{4}[-][a-z0-9]{4}[-][a-z0-9]{12})";
    
                MatchCollection mc = Regex.Matches(body, pattern);
    
                List<Guid> output = new List<Guid>();
                foreach (Match match in mc)
                {
                    output.Add(new Guid(match.ToString()));
                }
                return output;
            }
    
    
    
    
    public static List<Guid> RetrieveResourcesGUIDs(IOrganizationService Service, Guid ServiceID)
            {
                EntityCollection serviceCollection = CrmCrudHelper.RetrieveService(Service, ServiceID);
                if (serviceCollection.Entities.Count > 0)
                {
                    // Get Resource GUIDs
                    Entity serviceEntity = serviceCollection.Entities[0];
                    AliasedValue constraintbasedgroup2 = (AliasedValue)serviceEntity["constraintbasedgroup2.constraints"];
                    List<Guid> resourcegroupGUIDS = XmlHelper.ExtractIGUIDs(constraintbasedgroup2.Value.ToString());
    
                    EntityCollection resourcegroupCollection = RetrieveResourceGroups(Service, resourcegroupGUIDS);
                    if (serviceCollection.Entities.Count > 0)
                    {
                        List<Guid> resourceGUIDS = new List<Guid>();
    
                        foreach (Entity resourcegroupEntity in resourcegroupCollection.Entities)
                        {
                    
                            AliasedValue constraintbasedgroup1 = (AliasedValue)resourcegroupEntity["constraintbasedgroup1.constraints"];
                            resourceGUIDS.AddRange(XmlHelper.ExtractIGUIDs(constraintbasedgroup1.Value.ToString()));
                        }
                        return resourceGUIDS;
                    }
                    else
                    {
                        throw new ApplicationException(String.Format("A Resource Group collection was NOT retieved for the GUID: \"{0}\"", ServiceID));
                    }
                }
                else
                {
                    throw new ApplicationException(String.Format("A Service record was NOT retieved for the GUID: \"{0}\"", ServiceID));
                }
            }

    Hope that helps anyone else who runs into this.


    Thursday, June 5, 2014 4:00 PM
  • Unfortunately you'll have to parse the XML yourself. The CRM SDK does not provide any methods to help you parse it

    Microsoft CRM MVP - http://mscrmuk.blogspot.com/ http://www.excitation.co.uk

    Thursday, June 5, 2014 1:42 PM
    Moderator

All replies

  • Unfortunately you'll have to parse the XML yourself. The CRM SDK does not provide any methods to help you parse it

    Microsoft CRM MVP - http://mscrmuk.blogspot.com/ http://www.excitation.co.uk

    Thursday, June 5, 2014 1:42 PM
    Moderator
  • Had feared that :)

    Wrote an XML function to deal with it and it was fairly painless.

    internal static List<Guid> ExtractIGUIDs(string Xml)
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Xml);
    
                XmlNode node = doc.SelectSingleNode("/Constraints/Constraint/Expression/Body");
                string body = node.InnerText;
    
                string pattern = @"([a-z0-9]{8}[-][a-z0-9]{4}[-][a-z0-9]{4}[-][a-z0-9]{4}[-][a-z0-9]{12})";
    
                MatchCollection mc = Regex.Matches(body, pattern);
    
                List<Guid> output = new List<Guid>();
                foreach (Match match in mc)
                {
                    output.Add(new Guid(match.ToString()));
                }
                return output;
            }
    
    
    
    
    public static List<Guid> RetrieveResourcesGUIDs(IOrganizationService Service, Guid ServiceID)
            {
                EntityCollection serviceCollection = CrmCrudHelper.RetrieveService(Service, ServiceID);
                if (serviceCollection.Entities.Count > 0)
                {
                    // Get Resource GUIDs
                    Entity serviceEntity = serviceCollection.Entities[0];
                    AliasedValue constraintbasedgroup2 = (AliasedValue)serviceEntity["constraintbasedgroup2.constraints"];
                    List<Guid> resourcegroupGUIDS = XmlHelper.ExtractIGUIDs(constraintbasedgroup2.Value.ToString());
    
                    EntityCollection resourcegroupCollection = RetrieveResourceGroups(Service, resourcegroupGUIDS);
                    if (serviceCollection.Entities.Count > 0)
                    {
                        List<Guid> resourceGUIDS = new List<Guid>();
    
                        foreach (Entity resourcegroupEntity in resourcegroupCollection.Entities)
                        {
                    
                            AliasedValue constraintbasedgroup1 = (AliasedValue)resourcegroupEntity["constraintbasedgroup1.constraints"];
                            resourceGUIDS.AddRange(XmlHelper.ExtractIGUIDs(constraintbasedgroup1.Value.ToString()));
                        }
                        return resourceGUIDS;
                    }
                    else
                    {
                        throw new ApplicationException(String.Format("A Resource Group collection was NOT retieved for the GUID: \"{0}\"", ServiceID));
                    }
                }
                else
                {
                    throw new ApplicationException(String.Format("A Service record was NOT retieved for the GUID: \"{0}\"", ServiceID));
                }
            }

    Hope that helps anyone else who runs into this.


    Thursday, June 5, 2014 4:00 PM