lookup原理


1. 大家都知道CRM 里面的Lookup 保存了相关实体的GUID,让我们深入的了解一下CRM Lookup。当我们在2个实体间建立关系的时候,CRM自动生成了一些attributes来保存相关实体的信息,虽然我们在CRM定制界面只能看到一个 attribute,也就是保存GUID的那个,其实CRM还创建了一些隐含的attributes来保存其他信息,来看一个例子:

crmForm.all.regardingobjectid.DataValue[ 0 ].id;   //  The GUID of the lookup.
crmForm.all.regardingobjectid.DataValue[ 0 ].name;   //  The text value of the lookup.
crmForm.all.regardingobjectid.DataValue[ 0 ].typename;   //  The entity type name.

 

 


这也就是为什么我们可以引用除了GUID的其他相关信息,这些隐含的attributes可以通过导出实体的customisation.xml 来看到。
也许有人注意到了,在CRM里,所有user-owned entity(比如 account, contact, case, email etc) 都有一个系统attribute叫做 ownerbusinessunit,这也是个Lookup,但却是系统的Lookup。这个attribute用来记录记录所有者(the owner)所在BusinessUnit的GUID。CRM论坛里一个常见的问题就是怎样得到当前用户的BusinessUnit,最常用的方法是通过AJAX来得到,见我以前的Blog有提。其实我们可以利用ownerbusinessunit来做,方法是导出customisation.xml 进行修改然后导入,这样才可以把ownerbusinessunit加到窗体上。注意这种方法只能得到GUID,不能得到BU's Name,原因上面已经说了,因为是系统的Lookup,CRM没有创建Name这个attribute。到此为止这种方法是比AJAX来的简单,但如果要得到BU's Name就不如食用AJAX了。

 



2. 我们来看看regardingobjectid这个特殊的Lookup,当用户选择Regarding的时候,也许那个下拉菜单会有很多选项:Account, Contact, Opportunity, Lead.... ,如果我只想显示Account 和Contact,并且把默认值设定为Contact怎么办呢? 在onLoad() 里面写如下语句:

crmForm.all.regardingobjectid.setAttribute( " lookuptypes " " 1,2 " );   // only show account and contact
crmForm.all.regardingobjectid.setAttribute( " lookuptypeIcons " " /_imgs/ico_16_1.gif :/_imgs/ico_16_2.gif " );   // set the icons
crmForm.all.regardingobjectid.setAttribute( " defaulttype " " 2 " );   // default to contact

 

 


除了使用setAttribute 方法,还可以使用CRM自己的方法:

crmForm.all.regardingobjectid.lookuptypes  =   " 1,2 " ;    
  crmForm.all.regardingobjectid.lookuptypeIcons 
=   " /_imgs/ico_16_1.gif:/_imgs/ico_16_2.gif " ;
crmForm.all.regardingobjectid.defaulttype 
=   " 2 " ;  

 

 



3. 如果你注意一下Lookup的地址URL,你会发现CRM是这样调用的:
/lookupsingle.aspx?class=ActivityRegarding&objecttypes=1,2,3,4&browse=0&ShowNewButton=1&ShowPropButton=1&DefaultType=0

lookupsingle.aspx有一些参数可以被我们所用(ISV, IFRAME):

Objecttypes 实体代码, e.g. Objecttypes = "1, 2" //show account and contact
      DefaultType 默认实体代码, e.g. DefaultType = "2" //default to contact
      Browse  布尔值,  0 = 显示"查找" 栏; 1 = 浏览模式, 隐藏 "查找" 栏.
      ShowNewButton 布尔值,  0 = 隐藏 "新建" 按钮; 1 = 显示 "新建" 按钮.
      ShowPropButton 布尔值,  0 =  隐藏 "属性" 按钮; 1 = 显示 "属性" 按钮.

在IFRAME或者ISV里,如果我们不想显示"新建" 按钮,那么可以把URL调用写成:
/lookupsingle.aspx?class=ActivityRegarding&objecttypes=1,2,3,4&browse=0&ShowNewButton=0&ShowPropButton=1&DefaultType=0

但是如果我想在CRM里面隐藏 "新建" 按钮怎么办呢?你不能直接使用 crmForm.all.regardingobjectid.ShowNewButton = 0; 但是可以在onLoad()里使用下面的方法:

/*
   显示/隐藏 "新建" 按钮
   bShow = 0 : 隐藏 "新建" 按钮
   bShow = 1 :  显示 "新建" 按钮
*/

function  NewButton(bShow)
{
    
return function()
    
{
        crmForm.all.regardingobjectid.AddParam(
"ShowNewButton", bShow);
    }

}

crmForm.all.regardingobjectid.attachEvent(
" setadditionalparams " ,NewButton( 0 ));

 

 

4. 现在我们来看看Lookup的条件过滤,CRM3和CRM4有很大不同,我们通过例子来说明:
我们用的例子是:在公司(Account)记录里的主要联系人(primarycontactid) Lookup列表里只显示和这条公司记录(Account)有关联的联系人(Contact)。
 
a. CRM 3.0 

/* CRM 3.0: only show account owned contacts in the primarycontactid lookup : Form.onLoad() */  
if  (crmForm.FormType  ==   2   &&  crmForm.ObjectId  !=   null )
{
    crmForm.all.primarycontactid.lookupbrowse 
= 1;
    crmForm.all.primarycontactid.additionalparams 
= "fetchXml="
    
+ "<fetch mapping='logical'><entity name='contact'><all-attributes /><filter>"
    
+ "<condition attribute='accountid' operator='eq' value='" + crmForm.ObjectId + "' />"
    
+ "</filter></entity></fetch>";
}

 
b. CRM 4.0
 
据我目前了解,在CRM4.0里主要有两种unsupported customization可以进行这样的过滤。由于这个例子并不需要复杂的FetchXml查询,所以我们用第一种方法:
 
(1) 定制联系人(Contact) 实体, 打开 Contacts Lookup View,  点击'添加新的搜索栏'( Add Find Column),  选择parentcustomerid,保存并发布。
(2) 定制公司 (Account) 实体,在onLoad()里面添加如下代码:

/* CRM 4.0: only show account owned contacts in the primarycontactid lookup : Form.onLoad() */  
if  (crmForm.FormType  ==   2   &&  crmForm.ObjectId  !=   null )
{
    
var name = crmForm.all.name.DataValue;
    crmForm.all.primarycontactid.additionalparams 
=  'search=' + name;
}

这里使用到了‘search’参数,它的作用相当于用户在搜索栏填写了搜索内容。这里的搜索内容就是‘公司名’,由于我们在第一步已经将公司名添加到了搜索关键字栏,所以这个lookup将返回我们指定的公司(Account)记录。
 
现在如果我们把要求改变一下:只显示和这个公司(Account)的上级公司(parentaccountid)有关联的联系人(Contact)。
第一步是一样的,第二步改成如下代码:

/* CRM 4.0: only show parent account owned contacts in the primarycontactid lookup : Form.onLoad() */  
FilterLookup 
=   function (source, target)
{
    
if (IsNull(source) || IsNull(target)) return; }
    
var name = IsNull(source.DataValue) ? '' : source.DataValue[0].name;
    target.additionalparams 
= 'search=' + name;
}
 


上级公司(parentaccountid)也是一个Lookup,我们还要在它的 onChange()里面添加代码:

/* CRM 4.0: only show parent account owned contacts in the primarycontactid lookup : parentaccountid.onChange() */  
FilterLookup(crmForm.all.parentaccountid, crmForm.all.primarycontactid);

  
Ok, 现在问题解决了!
  
如果我们再改变一下要求:我们希望当用户选择了上级公司(parentaccountid)后,这个上级公司主要联系人(primarycontactid) 自动填充到当前公司(account)的主要联系人里。
 
虽然我们可以使用 AJAX 技术来达到这个目的,CRM4.0为我们提供了一个更酷的特性:Lookup自动填充(automatic resolutions)功能。
感谢 Adi Katz, 让我们从头开始来实现它:
 
(1) 关闭上级公司(parentaccountid) 的自动填充功能(automatic resolutions in field),只需要在Form上双击parentaccountid区域,然后在第一页就可以看到选项来取消这个功能。
(2) 在Form.onLoad()里面输入如下代码:

function  OnAfterAccountSelect()
{
    
var contactLookup  = crmForm.all.primarycontactid;
    
if( contactLookup.DataValue != null ) {return;}
         
    contactLookup.AutoResolve 
= 1;
    
var accountLookup = crmForm.all.parentaccountid;
    primaryContact 
= accountLookup.items[0].keyValues.primarycontactid;
     
    contactLookup.SetFocus();
    contactDiv 
= document.all.primarycontactid_d.getElementsByTagName("DIV")[0];
    contactDiv.innerText 
= primaryContact.value;
    contactLookup.Lookup( 
true , true , primaryContact.value , true );
}

 
function  OnCrmPageLoad()

    crmForm.all.parentaccountid.attachEvent( 
"onafterselect" , OnAfterAccountSelect );
}
 
 
OnCrmPageLoad();


Ok! 所有问题都解决了。一开始提到的CRM 4.0复杂的FetchXml过滤功能将在下一篇blog里详细解释。:)

 

 

 

5.       现在我们来看一个普遍应用的例子:我只想在regardingobjectidLookup里列出OpenCase

 

a.       CRM 3.0

 

 

/* set the regarding to open case : Form.onLoad() */
crmForm.all.regardingobjectid.lookuptypes 
=   " 112 " ;
crmForm.all.regardingobjectid.lookuptypeIcons 
=   " /_imgs/ico_16_112.gif " ;
 
/* only show the active cases : Form.onLoad() */
if  (crmForm.ObjectId  !=   null )
{
    crmForm.all.regardingobjectid.lookupbrowse 
= 1;
    crmForm.all.regardingobjectid.additionalparams 
= "fetchXml="
    
+ "<fetch mapping='logical'><entity name='incident'><all-attributes /><filter>"
    
+ "<condition attribute='statecode' operator='eq' value='0' />"
    
+ "</filter></entity></fetch>";
}


 

b.      CRM 4.0

 

4.0里,上述功能(additionalparams)不再可以使用,但是我们仍然可以使用上一篇文章提到的技术:打开Case Lookup View, 点击'添加新的搜索栏'( Add Find Column),  选择statecode,保存并发布。然后在Form.onLoad()里面输入如下代码:

 

/* set the regarding to open case : Form.onLoad() */
crmForm.all.regardingobjectid.lookuptypes 
=   " 112 " ;
crmForm.all.regardingobjectid.lookuptypeIcons 
=   " /_imgs/ico_16_112.gif " ;
crmForm.all.regardingobjectid.additionalparams 
=   ' search=Active ' ;

 

大家已经看到了,像这种简单的Filter功能用这个技术就可以实现。但是如果想实现复杂一点的呢?
比如我们现在的要求变成了:只列出当前用户的
Open Case!


像这样复杂一些的
Filter功能我们一般先用高级查找(Advanced Find)Build FetchXml,然后再进行下一步。具体做法在Ronald Lemmen Blog里有讲:就是在搜索结果的IE地址栏里输入如下代码:javascript:prompt("", resultRender.FetchXml.value);


这样会弹出一个
JavaScript.pormpt窗口,具体到我们的这个例子弹出的FetchXml语句是:


<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false"><entity name="incident"><attribute name="title"/><attribute name="ticketnumber"/><attribute name="createdon"/><attribute name="incidentid"/><order attribute="title" descending="false"/><filter type="and"><condition attribute="statecode" operator="eq" value="0"/><condition attribute="ownerid" operator="eq-userid"/></filter></entity></fetch>


下面介绍的在
CRM 4.0里面的FilteredView功能最先是Adi Katz开发的,然后网友George进行了一些改进。我拿改进好的版本给大家演示:(注:下面的定制方法属于非常Unsupported的那种Customizationidea是重载了code-behind 的程序,加一个Filter进去。CRM 4.0 目前只有一种基于Filtered Lookup Supported Customization,是Michael Höhne开发的收费插件


你需要修改这个文件:
CRMWeb//_controls//lookup//lookupsingle.aspx,加入下面的代码:

 

< script runat = " server " >
protected   override   void  OnLoad(EventArgs e)
{
    
base.OnLoad(e);
    crmGrid.PreRender 
+= new EventHandler(crmGrid_PreRender);
}

void  crmGrid_PreRender( object  sender, EventArgs e)
{
    
if (crmGrid.Parameters["search"!= null && crmGrid.Parameters["search"].StartsWith("<fetch")) 
    

        crmGrid.Parameters.Add(
"fetchxml", crmGrid.Parameters["search"]);  
        crmGrid.Parameters.Remove(
"searchvalue");  
        
this._showNewButton = false
    }
 
}

</ script >



然后在


 

/* set the regarding to open case which owned by current user : Form.onLoad() */
crmForm.all.regardingobjectid.lookuptypes 
=   " 112 " ;
crmForm.all.regardingobjectid.lookuptypeIcons 
=   " /_imgs/ico_16_112.gif " ;
 
var  fetchStr  =   " <fetch version= " 1.0 "  output-format= " xml - platform "  mapping= " logical "  distinct= " false " ><entity name= " incident " ><attribute name= " title " /><attribute name= " ticketnumber " /><attribute name= " createdon " /><attribute name= " incidentid " /><order attribute= " title "  descending= " false " /><filter type= " and " ><condition attribute= " statecode "  operator= " eq "  value= " 0 " /><condition attribute= " ownerid "  operator= " eq - userid " /></filter></entity></fetch> " ;
crmForm.all.regardingobjectid.lookupbrowse 
=   1 ;
crmForm.all.regardingobjectid.additionalparams 
=   " search= "   +  fetchStr;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值