Thursday, November 18, 2010

Filter Lookup for N:N relation




My Scenario is i have loaded an area in an IFrame. 

Three entities are invloved in this:
Account, demo, testmodel.

Account <--> demo N:N relation
Account <--> testmodel N:N relation
testmodel <--> demo 1:N relation


Now, N:N between account and testmodel is loaded in an iframe and,
N:N between account and demo is loaded in another iframe, both in account form. 

Scenario is we need to filter the lookup such as demo lookup gives us only those demo records which are associated to the selected testmodel record in testmodel iframe in account form. 

Filtering this N:N relation lookup invloves two steps:
  1. customization in the onload script of the primary entity.
  2. registering a plugin on execute event
Note that this method is unsupported because we will be calling internal js in the server to associate the records.
JScript:


///CODE TO LOAD CUSTOM LOOKUP FROM AREA IN IFRAME

var relId = "new_new_demo_account";

var lookupId = crmForm.ObjectId ;  

var lookupEntityTypeCode;
var navId = document.getElementById("IFRAME_" + relId);

//navId has to be the IFrame. NAme accordingly
if (navId != null)
{
    
    navId.onreadystatechange = function()
    {

     if (navId.readyState == "complete"){

var areaId = document.getElementById("mnuBar1");
        if(areaId != null)
        {
                    var frame = frames[window.event.srcElement.id];  
                    var li = frame.document.getElementsByTagName("li");    

                    for (var i = 0; i < li.length; i++)
                    {
                        var action = li[i].getAttribute("action");
                        if(action != null && action.indexOf(relId) > 1)
                        {
                            lookupEntityTypeCode = action.substring(action.indexOf("\(")+1, action.indexOf(","));
                            li[i].onclick = CustomLookup;
                            break;
                        }
                    }
          }
        }
    }
}

function CustomLookup()
{

    var lookupSrc = "/" + ORG_UNIQUE_NAME + "/_controls/lookup/lookupmulti.aspx?class=&objecttypes=" + lookupEntityTypeCode + "&browse=0";
    if(lookupId != null )
    {
        lookupSrc = lookupSrc + "&id=" + lookupId;
    }

    var lookupItems = window.showModalDialog(lookupSrc, null);
    if (lookupItems)  
    {
        if ( lookupItems.items.length > 0 )
        {
// This is the CRM internal JS funciton on \_static\_grid\action.js  This is for N:N non self referential relationships. UNSUPPORTED
            AssociateObjects( crmFormSubmit.crmFormSubmitObjectType.value, crmFormSubmit.crmFormSubmitId.value, lookupEntityTypeCode, lookupItems, true, null, relId);
//Incase of selfreferential relationships, you need to pass use the below coxde.
// AssociateObjects( crmFormSubmit.crmFormSubmitObjectType.value, crmFormSubmit.crmFormSubmitId.value, lookupEntityTypeCode, lookupItems, false, null, relId);
        }
    }
}




Plugin


Two fetchxmls are used in this plugin. First, we retrieve the id from the url of the customlookup and execute one fetchxml for retrieving the testmodel records associated with the account. 


second fetchxml is for getting demo records associated with the result of first fetchxml testmodels. 


Ultimately, we will just replace the fetchxml present in the execute event with the second xml. The plugin has to be registered on Pre-Stage of execute with primaryentity none and secondaryentity none. 


Note: Execute is the common event used for many CRM service calls. So the catch here is that we need to check for the existence of the parameter 'id' in the context before proceeding with the execution. 


An additional check as to whether the id belongs to the particular objecttype for which you are executing the plugin would also help. 




CODE:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using System.Web;
using System.Xml;
using System.Net;
using System.Web.Caching;


namespace ExecuteClassLibrary
{
    public class Class1:IPlugin
    {    
        string lookupId;

        public void Execute(IPluginExecutionContext context)
        {

            lookupId = HttpContext.Current.Request.QueryString["id"] == null ? null : HttpContext.Current.Request.QueryString["id"].ToString();

            
            if (lookupId == null)   return;

            try
            {
                if (context.InputParameters.Contains("FetchXml"))
                {
                    string beforeXml = (String)context.InputParameters["FetchXml"];

                    if (beforeXml.Contains("<entity name=\"new_demo\">") && beforeXml.Contains("xml-platform"))
                    {
                        //GET VALUES FROM N:N TABLE FIRST

                        string fetchXml = "<fetch version='1.0' page='1' count='100' output-format='xml-platform' mapping='logical'> " +
                                        "<entity name='new_account_new_testmodel'> " +
                                            "<attribute name='new_testmodelid' /> " +
                                            "<filter type='and'> " +
                                                    "<condition attribute = 'accountid' operator='eq' value='"+ lookupId+ "'/>" +  //lookupId + "'/> " +
                            //"<condition attribute='new_name' operator='like' value='%' /> " +
                                            "</filter> " +
                                        "</entity> " +
                                    "</fetch>";
                        CrmService crmservice = context.getCrmService();

                        ExecuteFetchRequest req = new ExecuteFetchRequest();
                        req.FetchXml = fetchXml;
                        ExecuteFetchResponse resp = (ExecuteFetchResponse)crmservice.Execute(req);
                        // string retXml = crmservice.Fetch(fetchXml);
                        XmlDocument fxml = new XmlDocument();
                        fxml.LoadXml(resp.FetchXmlResult);
                        string value = string.Empty;

                        foreach (XmlNode node in fxml.ChildNodes)
                        {
                            foreach (XmlNode childnode in node.ChildNodes)
                            {
                                foreach (XmlNode resultnode in childnode)
                                {
                                    if (resultnode.Name == "new_testmodelid")
                                    {
                                        value += "<value>" + resultnode.ChildNodes.Item(0).InnerText + "</value>";
                                    }
                                }
                            }
                            //node
                        }


                        //Customise the FetchXml query string
                        string afterXml =
                        "<fetch version='1.0' page='1' count='100' output-format='xml-platform' mapping='logical'> " +
                            "<entity name='account'> " +
                                "<attribute name='name' /> " +
                                "<attribute name='accountid' /> " +
                                "<attribute name='createdon' /> " +
                                "<order attribute='name' /> " +
                                "<filter type='and'> " +
                                        "<condition attribute = 'new_soperator' operator='neq'>" + value + "</condition> " +
                                        "<condition attribute='statecode' operator='eq' value='0' /> " +
                                "</filter> " +
                            "</entity> " +
                        "</fetch>";

                        //Replace the FetchXml query string
                        context.InputParameters["FetchXml"] = beforeXml.Replace(beforeXml, afterXml);

                    }
                }
            }

            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the CRM plug-in.", ex);
            }
        }

    }
}




No comments:

Post a Comment