CRM2011
CRM基本信息
CRM字段类型:
货币:new Money(Decimal){SQL更新Money类型字段,需要同时更新_base字段,存在汇率差的时候值不同}
查找:new EntityReference(objecttypename,Guid)
下拉:new OptionSet(Int)
选项集:false=0/true=1
状态:statecode(可用0/禁用1)
时间:DateTime
整数:Integer
十进制数:Decimal
浮点数:Double
单行/多行文本:String
1.orgService.Create(a.boc_name=null || a.boc_name=""),插件中判断boc_name=null
2.orgService.Update(a.boc_name=null || a.boc_name=""),插件中判断boc_name=""
CRM常用表和设置:
存储列表值:StringMap
存储附件:annotation
存储SDKMessageStep:SdkMessageProcessingStep
存储实体: MetadataSchema.Entity
存储字段: MetadataSchema.Attribute
存储视图:dbo.SavedQueryBase / dbo.UserQueryBase
存储表和仪表板:SystemFormBase
存储用户:dbo.SystemUserBase [ActiveDirectoryGuid使之与域用户唯一绑定]
用户设置表: UserSettings
时区对应视图:TimeZoneDefinition(TimeZoneCode)
时区规则视图:TimeZoneRule(TimeZoneDefinitionId)
系统作业:AsyncOperationBase
作业状态statecode(0=准备就绪;1=暂停;2=已锁定;3=已完成)
作业状态描述statuscode(0=正在等待资源;10=等待中;20=正在进行;21=正在暂停;22=正在取消;30=成功;31=失败;32=已取消)
其他字段:Message,ErrorCode,
流程日志:WorkflowLogBase
状态status(1=正在进行;2=成功;3=失败;4=已取消;5=等待中)
早期绑定:Account acc=new Account();
晚期绑定:Entity acc=new Entity("account");
未发布:字段ComponentState=1,发布后删除为0,并改为0
--导出Excel最条数大限制(*_MSCRM)默认1W条
select MaxRecordsForExportToExcel from dbo.OrganizationBase
--JS查询最大条数限制(MSCRM_CONFIG)
select intcolumn from ServerSettingsProperties where ColumnName = 'MaxResultsPerCollection'
--视图记录总数(MSCRM_CONFIG),可以设置不显示,提高性能
select TotalRecordCountLimit from DeploymentProperties
--视图每页显示数量(*_MSCRM)
select PagingLimit from UserSettings
需要重启IIS
select * from test_MSCRM..sysobjects,查询库中所有表、函数、视图
查找CRM视图的ID:select * from savedquery / select * from userquery
取CRM系统orginationid,systemuserid:
select top 1 @orgid=OrganizationId,@sysuserid=SystemUserId from dbo.OrganizationBase with (nolock)
移出Form表单上的已锁定字段:select * from systemformbase
调试插件-w3wp
调试流程(工作流)-CrmAsyncService
调试流程(脚本)-w3wp
1.发现服务-http://crmpc/XRMServices/2011/Discovery.svc (用来发现域下面有哪些组织)
2.SOAP组织服务-http://crmpc/yto/XRMServices/2011/Organization.svc (C#使用的标准的数据服务)
3.OData组织服务-http://crmpc/yto/XRMServices/2011/OrganizationData.svc (平时使用的rest脚本数据服务)
CRM_Plugin_Message:
Associate 创建多对多关系(要判断Relationship)
(EntityReference)context.InputParameters["Target"] / (Relationship)context.InputParameters["Relationship"] / (EntityReferenceCollection)context.InputParameters["RelatedEntities"]
Associate注释:系统Associate或者Dis,都是一条条进行的,也就是RelatedEntities只包含一条数据,且每一条一个事务。
给Team添加User,或者给User添加角色:如果User是禁用的会报错:User Id is invalid.
如果已存在关系,会报错:Cannot insert duplicate key.
Create 创建数据
Delete 删除数据 InputParameters [“Target”]= EntityReference
Disassociate 删除多对多关系(要判断Relationship)
Execute 执行请求
Retrieve 查询一个记录
(ColumnSet)context.InputParameters["ColumnSet"] / (Entity)context.OutputParameters["BusinessEntity"]
RetrieveMultiple 查询多个记录
context.InputParameters["Query"] as QueryExpression / context.InputParameters["Query"] as FetchExpression / (EntityCollection)context.OutputParameters["BusinessEntityCollection"]
Update 更新数据
其他的数据操作:
1.Assign分派
(EntityReference)context.InputParameters["Target"] / (EntityReference)context.InputParameters["Assignee"]
注意:Assignee中Name无值,PostImage/PreImage中Lookup的Name有值。
2.修改状态SetStateRequest
获取实体:
EntityReference entity = context.InputParameters.Contains("EntityMoniker") ? context.InputParameters["EntityMoniker"] as EntityReference : null;
获取状态:
OptionSetValue state = context.InputParameters["State"] as OptionSetValue;
OptionSetValue status = context.InputParameters["Status"] as OptionSetValue;
修改状态:(完成任务1+5;取消任务2+6)
SetStateRequest setState = new SetStateRequest();
setState.EntityMoniker = new EntityReference("task", task1.Id);
setState.State = new OptionSetValue(1);
setState.Status = new OptionSetValue(5);
testService.Execute(setState);
3.多对对,N对N,添加关系:
EntityReferenceCollection coll=new EntityReferenceCollection();
coll.Add(new EntityReference("systemuser",new Guid("1DCCAD1E-9F67-E311-93EF-002481E88330")));
testService.Associate("team", new Guid("99C72A6E-EA71-E311-93FD-002481E8832E"), new Relationship("teammembership_association"), coll);
已存在关系,会报错。
4.执行工作流ExecuteWorkflowRequest
ExecuteWorkflowRequest request = new ExecuteWorkflowRequest()
{
WorkflowId = new Guid("C4745DA5-CA92-4E37-9A63-0F3BC73ECB06"),
EntityId = new Guid("C68B84F8-D397-E311-93FD-002481E8832E")
};
ExecuteWorkflowResponse response = (ExecuteWorkflowResponse)testService.OrganizationService.Execute(request);
5.分配权限GrantAccessRequest/ModifyAccessRequest/RevokeAccessRequest
(Revoke不存在的权限不报错,但Revoke前需要判断:Revokee不是Target的Owner)
var grantAccessRequest = new GrantAccessRequest
{
PrincipalAccess = new PrincipalAccess
{
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess,
Principal = manager
},
Target = new EntityReference("boc_financialalert", financialAlertId)
};
orgService.Execute(grantAccessRequest);
var revokeAccessRequest = new RevokeAccessRequest
{
Revokee = new EntityReference("systemuser", Guid.Parse(ParticipantId)),
Target = new EntityReference("boc_taskmanager", Guid.Parse(tmRes.ToString()))
};
6.1更改用户机构SetBusinessSystemUserRequest(Update无法修改用户机构)
6.2更改用户上级用户SetParentSystemUserRequest
6.3更改机构上级机构SetParentBusinessUnitRequest
SDK位置:SdkMessage 实体消息和方法
public void ChangeUserBu(Guid userId, Guid newBUId)
{
SetBusinessSystemUserRequest request = new SetBusinessSystemUserRequest();
request.BusinessId = newBUId;
request.UserId = userId;
request.ReassignPrincipal = new EntityReference(SystemUser.EntityLogicalName, userId); ;
IOrganizationService orgService = new ContextOrgService().Current;
orgService.Execute(request);
}
7.查询记录本身的权限信息RetrieveSharedPrincipalsAndAccessRequest
RetrieveSharedPrincipalsAndAccessRequest retrieveRequest = new RetrieveSharedPrincipalsAndAccessRequest();
retrieveRequest.Target = shareInfo.Entity.ToEntityReference();
var retrieveResponse = (RetrieveSharedPrincipalsAndAccessResponse)orgService.Execute(retrieveRequest);
var accesses = retrieveResponse.PrincipalAccesses;
8.异步批量删除BulkDeleteRequest
This job runs asynchronously in the background without blocking other activities.
BulkDeleteRequest deleteRequest = new BulkDeleteRequest();
deleteRequest.JobName = string.Format("ActionDelete for {0}", boc_actioncarrier.EntityLogicalName);
QueryExpression query = new QueryExpression(boc_actioncarrier.EntityLogicalName);
query.ColumnSet = new ColumnSet("activityid");
ConditionExpression condition = new ConditionExpression("activityid", ConditionOperator.Equal,id);
query.Criteria.AddCondition(condition);
deleteRequest.QuerySet = new QueryExpression[] { query };
deleteRequest.SendEmailNotification = false;
deleteRequest.ToRecipients = new Guid[] { currentUser.Id };
deleteRequest.CCRecipients = new Guid[] { currentUser.Id };
deleteRequest.RecurrencePattern = string.Empty;// To run the bulk delete job without recurrence, set this property to String.Empty.
deleteRequest.StartDateTime = DateTime.Now + new TimeSpan(0, 0, 20);
orgService.Execute(deleteRequest);
9.禁用用户
10.禁用机构
CRM脚本
1.Xrm.Page.context
用户ID:getUserId()
用户角色:getUserRoles()
用户语言:getUserLcid()
组织名称:getOrgUniqueName()
组织语言:getOrgLcid()
路径参数:getQueryStringParameters()
服务器路径:getServerUrl()/getClientUrl()
前追加组织名称:prependOrgName("/WebResource/**")效果:crmtest/WebResource/**
当前主题:getCurrentTheme()
OutLook:isOutlookClient()/isOutlookOnline()
2.Xrm.Page.data.entity
所有页面元素:attributes【forEach(),get(),getLength()】
单个元素:attributes.get("")【同Xrm.Page.getAttribute()】
实体名称:getEntityName()
实体ID:getId()
是否修改:getIsDirty()
保存事件:save( null | "saveandclose" |"saveandnew" )
添加保存时事件:addOnSave()
移出保存时事件:removeOnSave()
3.Xrm.Page.getAttribute("")
取值:getValue()
赋值:setValue()
是否改动:getIsDirty()
表单载入时的值:getInitialValue()[Boolean, optionset]
提交类型:getSubmitMode(),setSubmitMode()//always,never,ditry
必填等级:getRequiredLevel(),setRequiredLevel()//required、none
用户操作等级:getUserPrivilege()//canCreate()、canRead()、canUpdate()
事件:addOnChange(),removeOnChange(),fireOnChange()[强制执行]
其他:getAttributeType(),getFormat(),getMax(),getMaxLength(),getMin(),getName(),getParent(),getPrecision()
optionset:getOption(),getOptions(),getSelectedOption(),getText()
4.Xrm.Page.getControl("")
属性:getAttribute()【同Xrm.Page.getAttribute()】
禁用/启用:setDisabled(true),setDisabled(false),getDisabled()
显示/隐藏:setVisible(true),setVisible(false),getVisible()
描述:setLabel(),getLabel()
聚焦选中:setFocus
刷新:refresh()//仅限SubGrid
其他:addCustomView(),addOption(),removeOption(value),clearOptions(),getControlType(),getData(),setData(),getDefaultView(),setDefaultView(),getName(),getParent(),getSrc(),setSrc(),getInitialUrl(),getObject()
5.Xrm.Page.ui
页面所有控件:controls【forEach(),get(),getLength()】
单个控件:controls.get("")【同Xrm.Page.getControl()】
页面Tab:tabs【forEach(),get(),getLength()】
单个Tab:tabs.get()【sections,getDisplayState(),getLabel(),getName(),getParent(),getVisible(),setDisplayState(),setFocus(),setLabel(),setVisible()】
Tab-Sections:tabs.get(0).sections【forEach(),get(),getLength()】
单个Section:tabs.get(0).sections.get(0)【getLabel(),getName(),getParent(),getVisible(),setLabel(),setVisible(),controls】
页面导航:navigation.items【forEach(),get(),getLength()】
单个导航:navigation.items.get()【getId(),getLabel(),getVisible(),setFocus(),setLabel(),setVisible()】
获取导航:1.通过getLabel()遍历;2.通过ID:.get("navContacts")
例:隐藏活动:Xrm.Page.ui.navigation.items.get("navActivities").setVisible(false)
document.getElementById(“navActivites”)
注:导航只能有5个,通过XML增加无法识别,“流程”的名字无法通过配置修改,只能用JS:document.getElementById("NA_PROC").innerHTML = "XXX";
窗体:formSelector.items【forEach(),get(),getLenght()】
单个窗体:formSelector.items.get()【getId(),getLabel(),navigate()-窗体跳跃】
var formItem = Xrm.Page.ui.formSelector.getCurrentItem();
6.Xrm.Utility
Xrm.Utility.openEntityForm(name,id,parameters) |
打开新帐户记录
Xrm.Utility.openEntityForm("account"); |
打开一个现有的客户记录
Xrm.Utility.openEntityForm("account","A85C0252-DF8B-E111-997C-00155D8A8410"); |
http://22.188.136.43/GCSPD-BOCDEV-WPI/main.aspx?etn=boc_financialalert&pagetype=entityrecord&id=%7B2ddc35a2-9b30-e511-8f0d-005056b91cd0%7D |
http://22.188.136.43/GCSPD-BOCDEV-WPI/userdefined/edit.aspx?etc=10729&id=%7b2ddc35a2-9b30-e511-8f0d-005056b91cd0%7d |
打开新帐户记录与特定窗体并设置默认值
var
parameters = {}; |
|
打开WebResource: Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height) |
|
window.showModalDialog(Xrm.Page.context.prependOrgName("/WebResources/boc_/Htmls/AuditPage.html"), "", "dialogWidth=350px;dialogHeight=260px; help=no;status=no;scroll=no"); |
|
window.showModalDialog("/WebResources/boc_/Htmls/AuditPage.html", "", "dialogWidth=350px;dialogHeight=260px; help=no;status=no;scroll=no"); 返回值:window.returnValue=”111”;colse(); |
|
var url = "/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultViewId=%7bF86239AE-C483-E211-B9C3-00155D332305%7d&DisableQuickFind=0&DisableViewPicker=1&ShowNewButton=1&ShowPropButton=1&LookupStyle=multi&browse=0&objecttypes=" + typeCode; var res = openStdDlg(Xrm.Page.context.prependOrgName(url), lookupViewArgs, 620, 690); |
|
打开Dialog: var url = Boc.Utility.ServerUtility.GetUrl() + "cs/dialog/rundialog.aspx?DialogId=%7b4EAE67F8-A787-4739-AAFB-46DB91AE7A08%7d&EntityName=systemuser&ObjectId=" + encodeURIComponent(Xrm.Page.data.entity.getId()); window.showModalDialog(url, "", "dialogWidth=600px;dialogHeight=400px"); //parent.location.href = parent.location.href; parent.close(); |
|
取Dialog的父窗体的参数: window.dialogArguments |
7.窗体状态
var FORM_TYPE_CREATE = 1;
var FORM_TYPE_UPDATE = 2;
var FORM_TYPE_READ_ONLY = 3;
var FORM_TYPE_DISABLED = 4;
var FORM_TYPE_QUICK_CREATE = 5;
var FORM_TYPE_BULK_EDIT = 6;
var formType = Xrm.Page.ui.getFormType();
8.脚本上下文
getContext() 返回Xrm.Page.context对象
getDepth() 返回一个值,指示在其中执行此处理程序的顺序
getEventArgs()
getSaveMode() 返回一个值,该值指示如何保存事件由用户初始化的。
isDefaultPrevented() 返回一个值,该值指示是否保存已取消事件,因为preventDefault在此事件处理程序或上一个事件处理程序时使用的方法。
preventDefault() 取消保存仍继续执行操作,但所有其他事件的处理程序。
getEventSource() 返回类似Xrm.Page.getAttribute对象,例:e.getEventSource().getValue()
getSharedVariable() 检索使用 setSharedVariable 的变量,例:ExecutionObj.getSharedVariable(key)
setSharedVariable() 设置当前处理程序完成后由处理程序使用的变量的值,例:ExecutionObj.setSharedVariable(key, value)
CRM函数
更多函数已经封装在【window】中
- 【函数】动态载入JS(CRM函数):loadScriptAdv("脚本URL","任意ID",false);
loadScriptAdv(Xrm.Page.context.prependOrgName("/WebResources/fw_rest"), "55EE635C-91BD-443F-A3E6-56ACEG4E574G", false);
- 【函数】获取Homepage选择的项(CRM函数,Array):getSelected("crmGrid");
机构Form特殊窗体获取用户SubGrid选中:document.getElementById("areaUsersFrame").contentWindow.getSelected("crmGridControl") - 【函数】刷新CRM视图:Mscrm.Utilities.refreshCurrentGrid(parseInt(Xrm.Page.context.getQueryStringParameters().etc));
获取当前Homepage实体code:Xrm.Page.context.getQueryStringParameters().etc
或者:Xrm.Page.getControl("Participant").refresh();
获取指定实体code:Mscrm.EntityPropUtil.EntityTypeName2CodeMap[实体名]
- 【函数】打开模式窗口openStdDlg()
AccessRights
AppendAccess |
The right to append the specified record to another object. Value = 0x10. |
AppendToAccess |
The right to append another record to the specified object. Value = 16. |
AssignAccess |
The right to assign the specified record to another user or team. Value = 0x80000. |
CreateAccess |
The right to create a record. Value = 0x20. |
DeleteAccess |
The right to delete the specified record. Value = 0x10000. |
None |
No access. Value = 0. |
ReadAccess |
The right to read the specified type of record. Value = 1. |
ShareAccess |
The right to share the specified record. Value = 0x40000. |
WriteAccess |
The right to update the specified record. Value = 2. |
管道阶段
事件管道分为多个阶段,其中有 4 个阶段可用于注册自定义开发的插件或第三方插件。在插件注册期间可以进一步在每个阶段对在该阶段中注册的多个插件进行排序(排名)
事件 |
阶段名称 |
阶段编号 |
说明 |
前期事件 |
前期验证 |
10 |
管道中的一个阶段,其中的插件在主系统操作之前执行。在此阶段注册的插件可能会在数据库事务外部执行。前期验证阶段在要执行的安全检查之前发生,以验证发出调用的用户或登录用户是否具有执行预期操作所需的正确权限。 |
前期事件 |
前期操作 |
20 |
管道中的一个阶段,其中的插件在主系统操作之前执行。在此阶段注册的插件将在数据库事务内部执行。 |
平台核心操作 |
主操作 |
30 |
系统的事务内主操作,例如创建、更新和删除等等。在该阶段中不可以注册自定义插件。仅供内部使用。 |
后期事件 |
后期操作 |
40 |
管道中的一个阶段,其中的插件在主系统操作之后执行。在此阶段注册的插件将在数据库事务内部执行。 |
后期事件 |
后期操作(已弃用) |
50 |
管道中的一个阶段,其中的插件在主系统操作之后执行。在此阶段注册的插件可能会在数据库事务外部执行。此阶段仅支持基于 Microsoft Dynamics CRM 4.0 的插件。 |
可以通过读取由传递到插件的 IPluginExecutionContext 继承的 IsInTransaction 属性来检查插件是否在事务中执行。如果插件在数据库事务中执行并且允许将异常传递回平台,则将回滚整个事务。阶段 20 和 40 一定是数据库事务的一部分,而阶段 10 和 50 可以是事务的一部分。
权限分析
- 访问权限
- 追加、追加到
1)
追加(N:1,多对一)
把该记录附加到另一记录
2)
追加到(1:N,一对多)
把另一记录附加到该记录
3) 实例
- 实体对注释,添加注释N:1实体关系:需要对注释有追加权限、对实体有追加到权限
- 添加客户认领移交申请N:1客户关系:该角色需要对“客户认领移交”有追加权限、对“客户”有追加到权限
- 添加联系人N:1存量客户关系:该角色需要对“联系人”有追加权限、对“存量客户”有追加到权限
- 优化所有查询语句(oData,SOAP,FetchXml,Sql)指定查询列
- 手动初始化的orginzationService需要Dispose()或者用Using()
优化方法
积累大全
注意
- 拼接SQL语句操作数据库时,必须考虑拼接过程中参数中是否会出现’号导致SQL语句无效,对于中文参数应该用SqlParameter处理参数。
- 创建实体
CRM:
1) 勾选“Activities”,活动实体的RegardingObjectId才可以选择该实体
- 先删除extensionbase,再删除base表数据
向Base表插入数据,必填字段:**Id,OrganizationId,statecode,statuscode - 删除SDK Step消息处理步骤
1) 通过CRM页面删除
2) 通过软件删除,需要同时删除Step和Step上级
- 不同角色查看不同的窗体:自定义-窗体-分配安全角色
完全自定义查看不同窗体:通过实现HttpModule - 是否出现“添加已存在**明细”按钮方法:明细表中主表字段的必填等级=业务必须,则不出现添加已存在按钮,否则出现。已有。
- 导入已存在的实体,处理下拉列表的方式是:根据新实体,完全覆盖现有实体。
- 打开CRM弹出:正等待审批电子邮件
设置-管理-系统设置-电子邮件-前两个勾
该审批,是审批用户的“电子邮件”字段,审批过后,用户的“主要电子邮件状态”会变化。 - 解决方案-导出翻译: 字段语言切换,包括按钮的标签,和全局按钮的标签:
- 应用程序功能区:CRM全局按钮的控制。(处理语言切换用导出翻译)
- 报表的中英文:用编辑报表时的属性“Languages”来实现,选不同的语言则只在对应语言时显示,并不实现切换。
- 编辑仪表板,节无法对齐,把高度或宽度升到最大,然后递减。
- 更改用户个性化设置-时区(其余时区相关字段会自动计算):
Entity entity = new Entity("usersettings"); entity.Id = new Guid("301CC74F-8FD3-E311-AE33-080027C6417F");//systemuserid entity["timezonecode"] = 58;//时区[View:TimeZoneDefinition] entity["transactioncurrencyid"] = new EntityReference("transactioncurrency", new Guid(""));//货币 entity["localeid"] = 1033;//格式[查找方式:页面-用户设定-格式-F12] entity["uilanguageid"]=1033;//语言 entity["getstartedpanecontentenabled"]=false;//不显示入门窗格 |
- 更新Systemuser的domainname:entity["domainname"] = "APAC\\admin";
- 潜在顾客-授予资格-只能选择客户:更改conv_lead.aspx,在onload最后添加一行:
document.getElementById("crmOwnerLookup").attributes["lookuptypes"].value = 1; - The key specified to compute a hash
value is expired, only active keys are valid.
Key过期,解决办法:打开CRM部署管理器,禁用-启用服务器 - 遇到过的问题:客户A分派给用户U1,创建一条属于U1的通知提醒;然后分派给U2,U2上出现两条属于自己的通知提醒,这是因为通知提醒实体与客户间的分派级联,导致属于U1的通知提醒也分派给了U2.
- 用户没有创建实体A的权限,但是导入按钮还是会存在。只是导入的时候,在映射的实体列表中找不到A实体,无法导入。
- 从Target中取Entity的原理
CRM编程是一个请求响应模型,任何操作都是通过一个Request发起,一个Response返回结果,这个模型简单实用。所有请求类都是继承OrganizationRequest,所有响应都是继承OrganizationResponse类。继承类这两个类的子类所附加的属性,最后都会放到Parameters属性中,Parameters是个键值对集合。比如创建请求。它的请求类是:CreateRequest它比OrganizationRequest父类只多出一个属性:Target这个属性类型为Entity。这个属性最后会以下类似的方式存入到Parameters中request.Parameters["Target"] = request.Target;然后执行Plugin时将Parameters赋给了PluginExecutionContext.InputParameters当Plugin执行完成之后,返回ResponseCreateResponse有个id属性,它是记录ID。这个值会被保存在Request的Results集合里Plugin执行到Post阶段时,Results将被赋给PluginExecutionContext.OutputParameters所以我们可以通过PluginExecutionContext.OutputParameters["id"]能取到当前创建记录的ID。 |
- 系统导入功能,是异步执行。插件判断是否导入:targetEntity.Contains("importsequencenumber")
- 例:在A.PostCreate插件中(导入),调用了B的插件,B插件上抛出了未捕捉异常。则在A.PostCreate中无法使用A.ID,因为B的异常导致A创建失败
例外:改为A.PreCreate插件,给A的Target直接赋值可以成功,但导入还是会显示失败数:need to start a transaction before commit.
例外:改为A.PostCreate异步插件,A.ID就可以使用了,但因为是导入,就变成了异步调异步。 - 跨系统导入角色遇到过的问题:
描述:DEV向生产环境导入一个角色,失败,提示已经存在该角色名称:因为生产环境手工建了该角色,导致角色GUID不同。
讨论:不可以删除生产环境该角色,因为RoleId已经绑定了许多用户
解决:分别导出DEV和生产环境仅包含该角色的解决方案,复制DEV该角色下的内容到生产环境。 - preloadcache,是URL路径中的参数,优点:在10几秒之内重复刷新表单,该参数不变,页面和数据库不交互;在10几秒之后,或者重新打开表单,该参数变化。
- 给User或Businessuit更换上级部门,CRM会把User或Businessunit下的User的角色清空。
- 【httpModules】通过配置CRMWeb\web.confg的httpModules达到打开客户不同表单:
- 【runtime、assemblyBinding、依赖项】通过配置CRMWeb\web.config达到自动输出依赖DLL到Microsoft.NET\Framework:
- 用户属性
|
- 所有实体的OwnerIdName值,取自OwnerBase.Name。在导入组织时,OwnerBase.Name会跟随域上用户的姓名顺序映射。
C#
- C#:一种简单、现代、面向对象、类型非常安全、派生自C、C++和Java的编程语言。具有VB的易用性,C++的高性能、低级内存访问。
1) COM:Component Object Model,组建对象模型
2) IL:Intermediate Language,中间语言
3) IDE:Intergrated Development Environment,集成开发环境
4) CLR:Common Language Runtime,公共语言运行库
5) CTS:,通用类型系统
6) MVC(模型-视图-控制器),是构建应用程序的一种模型,提供了可测试性、灵活性、可维护性
7) 值类型(value type):变量直接存储其数据,存储在堆栈中;
引用类型(reference type):变量仅存储地址,对应的数据可以在该地址中找到,存储在托管堆上。
8) EXE:Executable,可执行文件;DLL(Dynamic Link Library),动态链接库
- 值类型和引用类型
1) 值类型
i. 整型:有符号sbyte,short,int,long,无符号byte,ushort,uint,ulong,分别为8,16,32,64位
ii. 浮点类型:float(32位单精度浮点),double(64位双精度浮点)
iii. decimal类型:decimal(128位高精度十进制数表示法)
iv. bool类型:bool
v. 字符类型:char(16位的Unicode字符)
2) 引用类型
i. object类型:object(根类型)
ii. string类型:string(Unicode字符串)
3) 理解:
i. 值类型:
int i = 10; int j = i; j = 20; //Print:i = 10; j = 20 |
ii. 引用类型:
QueenModel Q1, Q2; Q1 = new QueenModel(); Q1.EntityId = "10"; Q2 = Q1; Q2.EntityId = "20"; //Print:Q1.EntityId =
"20"; Q2.EntityId = "20"; |
- JSON和对象互转
1) JavaScriptSerializer
//转对象为JSON private static string ToJson(Object obj) { var serializer = new JavaScriptSerializer { MaxJsonLength = int.MaxValue }; return serializer.Serialize(obj); } //转DT为List再转为JSON private List<Dictionary<string, string>> TableToList(DataTable dt) { var dicList = new List<Dictionary<string, string>>(); foreach (DataRow dr in dt.Rows) { var dic = new Dictionary<string, string>(); foreach (DataColumn dc in dt.Columns) { var keyVal = dr[dc.ColumnName]; dic.Add(dc.ColumnName, keyVal != null ? keyVal.ToString() : null); } dicList.Add(dic); } return dicList; } |
//转JSON为对象CommonResult private static CommonResult ToCommonResult(string json) { var serializer = new JavaScriptSerializer(); return serializer.Deserialize<CommonResult>(json); } |
2) JsonConvert
using Newtonsoft.Json; //转JSON为CommonResults CommonResults b = JsonConvert.DeserializeObject<CommonResults>(res); //转JSON为List<AccountResults> List<AccountResults> c = JsonConvert.DeserializeObject<List<AccountResults>>(b.Message); |
- 安装共享程序集:
1) gacutil /I SharedDemo.dll /f
- SqlParameter[]如何使用Add方法动态添加参数
List<SqlParameter> para = new List<SqlParameter>(); para.Add(new SqlParameter(“@name”,”张三”)); para.Add(new SqlParameter(“@hobby”, DBNull.Value)); para.ToArray(); |
-
- <script type="text/javascript" src="ClientGlobalContext.js.aspx"></script>
- 刷新当前页面:
window.location.href = window.location.href;
window.location.reload(); - 禁用页面所有控件:
Xrm.Page.ui.controls.forEach(function (control, index) {
control.setDisabled(true);
}); - 禁用子窗体SubGrid
document.getElementById(subgridname+"_span").disabled=true - 禁用表单选择器
$("#crmFormSelector").attr("disabled", "disabled");
$("#formSelectorDropdown").remove(); - 阻止保存事件(需要执行上下文,不勾选也可以,方法直接加一个参数):
JS:
function My_PreventSaveFunction(eContext) {
eContext.getEventArgs().preventDefault();
}
- JS引用了REST等通用JS的方法,需在该实体的窗体库中引用通用JS。
拼写Odata,必须写明查询字段:&select=,否则返回所有字段,严重影响性能。 - 表单FORM页面上开发的web资源怎么获取FORM上的userId和entityId:window.parent
- 修改Homapage页面的视图选择字体颜色:
function changeViewNameColor(){
$('#crmGrid_SavedNewQuerySelector span').css("color","red");
}
- JS给日期控件赋值:Xrm.Page.getAttribute("yto_date").setValue(new Date()),但是JS取客户机时间,建议在JS赋值的基础上再用PreValidate插件
- REST查询需要的日期类型转换:var myDate = (new Date()).format("yyyy-MM-ddThh:mm:ss");
- 正则去除特殊字符(只保留汉字,字母,数字,空格,[],())
Regex.Replace(value.ToString(), @"[^a-zA-Z0-9()\[\]\u4e00-\u9fa5\s]", "");
- JS运算符:!!
var async = !!callback; 等同于:var async=callback?true:false; 解释:如果callback为null,则为false
- JS返回访问平台
navigator.platform
navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)
- 打开webresource的html并传入参数,必须encodeURIComponent
var para = encodeURIComponent("reportname=CRMFinancialTargetHistory&accountno=344669480"); window.open('navReportFinancial.html?data=' + para, '_blank', 'location=no,menubar=no,status=no,toolbar=no,resizable=yes,scrollbars=yes,width=1020,height=720,left=185'); |
- var res
= window.showModalDialog(window.location.protocol + "//" +
window.location.hostname + ":8081/SiteService/Htmls/AuditPage.html",
Xrm.Page.context.getUserLcid(),
"dialogWidth=350px;dialogHeight=280px;help=no;status=no;scroll=no");
window.location.host
window.location.hostname/IE8,ModenDialog下不带端口 - Homepage中如何加载公用JS:放在RibbonDiffXml ==> Action 中,libiary=**,Function='isNaN'
- 绑定Enter事件
//绑定Enter事件 $(document).keypress(function (e) { var eCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode; if (eCode == 13) { //fun }}); |
ajax:
AJAX(异步 JavaScript 和 XML)是用于创建交互式 Web 应用程序的 Web 开发技术。服务器请求是使用 XmlHttpRequest 对象在后台从浏览器发出的。尽管可以发送同步请求,但建议做法是发送异步请求。异步请求需要两个 JScript 函数:一个用于发送请求,另一个用于“回调”函数以处理响应。
$.ajax({
type: 'GET',//POST/GET(url带参数)
url: urlStr,
data: para,//var para ={name:’zhangsan’}
dataType: "JSONP",//JSONP用于跨域请求,非请勿加
async: false,//同步无效果
success: function (data) {},
failure: function (error) {},
complete: function (result) {}
});
转化Object、DataTable为JSON:
private static string ToJson(Object obj) { var serializer = new JavaScriptSerializer { MaxJsonLength = int.MaxValue }; return serializer.Serialize(obj); } private List<Dictionary<string, string>> TableToList(DataTable dt) { var dicList = new List<Dictionary<string, string>>(); foreach (DataRow dr in dt.Rows) { var dic = new Dictionary<string, string>(); foreach (DataColumn dc in dt.Columns) { var keyVal = dr[dc.ColumnName]; dic.Add(dc.ColumnName, keyVal != null ? keyVal.ToString() : null); } dicList.Add(dic); } return dicList; } |
webResource
- 按钮调用JS写法:$webresource:***.js
- webResource上Html引用已上传的JS资源,例如:
a)
boc_/Htmls/AuditPage.html
boc_/Jscripts/jquery1.7.1.min.js
引用方法:
<script type="text/javascript"
src="../Jscripts/jquery1.7.1.min.js"></script>
Plugin:
- 插件注册管道
验证前: 数据补充和验证
操作前: 核心操作前对其他数据进行变更、创建、删除(失败可回滚)
操作后: 验证数据执行情况,执行核心操作后的后继工作
- 插件执行顺序
以Execution Order优先,相同的,根据SdkMessageProcessingStepId排序 - PluginRegister工具调试步骤:Plugin Registration Tool => Profile => 保存ErrorDetail.txt => Stop Profile => Debug,加载ErrorDetail.txt和DLL => VS附加PlugRegistration.exe到进程 =>Debug Start
VS调试同步进程:w3wp.exe;调试异步进程:异步服务进程
但如果注册在Sandbox,调试:sandbox.workerprocess.exe(首先要修改注册表SandboxDebugPlugins=1)
.pdb(标志文件)文件放到bin\assembly位置
- 插件注册位置:
1)
数据库
同步引用DLL放到:Microsoft Dynamics CRM\CRMWeb\bin
异步引用DLL放到:Microsoft Dynamics CRM\Server\bin
最好,都放GAC,因为放Bin会导致iis重启
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\BOC.APACCRM.Core\v4.0_1.0.0.0__89000b1a9e83ed6a
如果不知道路径和文件夹名称,可以用vs工具gacutil.exe
/i ***.dll,安装到本机,然后找到文件夹
2)
磁盘
同/异步引用的DLL放到:
Microsoft Dynamics
CRM\Server\bin\assembly
3)
GAC
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\
- Plugin抛异常到页面:throw new InvalidPluginExecutionException("");
- Plugin取值:int statuscode = (preImageEntity.Attributes["statuscode"] as OptionSetValue).Value;
- Plugin删除了类文件,还需要去RegisterFile.crmregister删除对应的引用,否则会出现部署失败
- 高级查找-编辑列-F12未出现开发人员工具:IE-Internet选项-安全-Internet-自定义级别-允许网站打开没有地址或状态栏的窗口-禁用
- 删除记录,在PreDelete和PostDelete中,已经把与之关联的数据中包含它的字段都NULL了。查询与之关联的数据,不能再通过该字段。
- 插件异步:异步plugin需要异步服务执行,这个启动时间会比较慢。POST后才会去启动这个操作。另外,异步作业有个特点,就是可还原操作。出错了,改完数据或修正plugin,可以将操作继续执行。
- VS新建解决方案,选不了组织,因为本机不能识别CRM电脑名,要添加HOSTS映射:172.16.4.217 crmtest
- 导入解决方案之后,需要去检查关于扩展功能的插件有没有出现重复项,删除较早的,不然会出现审批之后,按钮不会改变的问题。
- 不要使用任何系统自带的字段,如状态描述、创建日期来当作单据的字段使用!
- 域用户需要在CRM部署管理器中加入CRM部署管理员,才能进行VS代码部署操作。
- 货币类型的字段赋值:=new Money(decimail) !!!,切记。
- VS链接项目发生安全性的问题,因为CRM服务器和本机的时间相隔超过5分钟。
- 同步插件:
Pre中,不能用entity.Id(当前记录ID)来做引用,因为目前该数据尚不存在。
Post中,可以使用当前记录ID
但如果在Post中创建记录B,再使用B的记录ID,同样会失败:不存在。
异步插件:
Post中,当前记录ID和其他记录ID都可以使用。 - VS解决方案不显示CRM视图:修改“解决方案.sln”文件,添加节点
GlobalSection(CRMSolutionProperties) = preSolution
SolutionIsBoundToCRM = True
EndGlobalSection
- 值为NULL的列查询后不包含在实体中:!Contains("")
- 实体创建的时候可以给ownerid赋值,但更新的时候给ownerid赋值不会更新,需要用Assign分派。
- 【误区】日期赋值:
entity["date1"]=entity["date2"]是对的(显示:2013.1.2;date1:2013.1.1 16:00:00 date2:2013.1.1 16:00:00);entity["date1"]=DateTime.Parse(entity["date2"].ToString())是错的(显示:2013.1.2 date1:2013.1.1 8:00:00已错 date2:2013.1.1 16:00:00)
entity["date1"] = DateTime.Now、entity["date1"] = DateTime.UtcNow,结果是一样的!(2013.1.1 16:00:00)
取值:(DB,Retrieve,Image,Entity上取的都是-8H的,只有页面显示已经+8H)所以JS中和CS中的比较一定要注意。
- 通过数据库还原新组织后,由于顶级组织改变,所有业务部门的guid会改变。
- CRM数据库新建视图后,给新用户权限,需‘授予’查询的实体和关联实体的视图的‘选择’权限就行了。
- 删除或者更新数据的时候,用最高权限的用户初始化的组织服务,避免当前用户没有删除权限。
- context.SharedVariables插件间的参数传递,注意context不同的时候,获取不到,所以最好用顶级context。
- 关于实体字段“货币”的赋值:service中create和update实体的时候,只要带上货币类型字段,“货币”会自动被赋值。
- 窗体上给webresource传入的参数,自动被转码了,取值需要decodeuri,多了data=;
- 通过accountToCreate.RelatedEntities.Add(letterRelationship,
relatedLettersToCreate);
可以在同一个事务中批量创建实体和它的关联实体。 - 在插件中用SQL查询数据,要加with (nolock),避免造成插件死锁。
- 对于一个肯定会失败的orgService(比如内部使用了throw)不能仅仅用catch,然后置之不理。
因为这个失败的orgService会导致orgService后期操作无法继续。 - preImage和Retrieve中的EntityReference.Name有值
target中的EntityReference.Name为NULL - 一、preDeleteOperation(20)和postDeleteOperation(40)中context.UserId是System,而不等于context.InitiatingUserId是Caller
二、Depth=2的context.InitiatingUserId并不是Depth=1的InitiatingUserId,还是需要用递归,获取parentContext=null的UserId(而不是InitiatingUserId) - 插件执行中由于orgService.Execute()报错,用catch之后,页面仍然会报错:Error:An error has occurred.
- [报表触发插件]用CRM创建的报表,不会触发RetrieveMutiple插件。
- Update Assembly,软件更新插件失败:缺少Plugin-in文件,需要先把dll放到server/bin/assembly目录下。
- [-2146233087]Only owner can revoke access to the owner.
解释:当你revoke的User是这个记录的Owner时,只能用User自己来执行这个请求。 - [-2147220953]
The object you tried to delete is associated with another object and cannot be deleted.
无法删除记录,因为该记录与其他记录关联。
解释:因为级联关系中配置了:删除-限制 - [20151109.BOC]
删除客户:Generic SQL error. DELETE 语句与 REFERENCE 约束"boc_account_boc_accountfilterqueue_entityid"冲突。该冲突发生于数据库"BOCGSP_MSCRM",表"dbo.boc_accountfilterqueueExtensionBase", column 'boc_entityid'。
原因:设计失误,删除客户之后,触发了级联删除的客户服务团队的Delete插件,在客户级联删除了accountfilterqueue之后,又通过EntitySecurityQueen创建了一条accountfilterqueue,导致最后执行删除Account的SQL因为外键约束失败。- 1. 常用函数
Pulgin_Error
SqlServer:
1) 追加100个’0’并截断到100个长度:select right(replicate('0',100) + 'AAA', 100)
2) SQL语句强制定义CPU使用数量: Select * from systemuser OPTION (MAXDOP 4)
3) Union select 会去重(有性能损失);union all select 不会。
4) 强制排序规则查询:select fullname from systemuser order by fullname COLLATE Chinese_PRC_90_CI_AI
5) 多语言查询SQL,从中文系统查询英文数据,例如:where boc_name=N’张三’
6) 日期格式转换:select format(getdate(),'yyyyMMdd')
7) CTE语句:放;号在前面,CTE后可直接select或者update
8) CTE的条件必须有索引,不然出不来数据
9) A,B,C三表关联查询,非常慢,可以A join B放临时表A`,并给A`创建索引,再关联C表
- 2. 常用语句
1)
Insert
*** Select***
insert System_CodeMapping select
'boc_compliancebill','boc_channel',tdcode,attributevalue,codedescription from System_CodeMapping where
AttributeName='boc_channel'
2)
查询出多条的:
select vendor_id,count(*) from table group by vendor_id having count(*)>2
3)
序号(不使用排序,性能更优):
select Row_Number() over (order by (select null)) as RowId
4)
从所有脚本中查询,哪个脚本操作了AccountExtensionBase
SELECT OBJECT_NAME(id) FROM sys.syscomments WHERE text LIKE
'%AccountExtensionBase%'
5)
Object_name函数,是从sys.objects中匹配表名(脚本名)
查询库中所有表名和行数
SELECT OBJECT_NAME(object_id) tablename,* FROM sys.partitions
ORDER BY rows desc
6)
重建索引
--重建大额交易索引
ALTER INDEX ndx_for_cascaderelationship_boc_BT_To_Customer_Relationship ON
boc_blocktradeinfoExtensionBase REBUILD with(MAXDOP = 8)
7)
- 常用设置
1) 数据库恢复模式:简单
2) 自动增长:增量500M以上(如果增量太小,导致容量经常扩大,需要消耗时间)
3) 备份:选压缩备份
4) 压缩日志:压缩日志无效,尝试修改数据库为简单模式再压缩
5) 正在还原…
一直显示正在还原处理方法:restore database XXX with recovery
- 多条记录拼接为一个字符串:
SELECT @re=@re+','+yto_name FROM yto_order
select @new_businessunit= stuff((select ';'+convert(varchar(50),businessunitid) from businessunit for xml path('')),1,1,'')
- 配置Oracle的链接服务器
1.Oracle Net Manager软件,添加一个服务命名 2.ODBC数据源,添加一个用户数据源,指向服务命名 3.Sql Server,添加链接服务器,产品名称:oracle,数据源:ODBC数据源名称。 Oracle查询: select * FROM OPENQUERY(SQL_ORACLE,'SELECT * FROM bidw.to_fk_store_sales_target_view ') SQL Oracle和SQL Server之间的关联查询: a left join b on a.X=b.X COLLATE Chinese_PRC_CI_AS 从链接服务器查询: |
- 多表关联update
(注意:红框内主表名必须一样)
- 7. SQL查询所有自定义SDKMessage
SELECT DISTINCT entity.name , entity.OriginalLocalizedName , step.sdkmessageidname , step.stage , step.rank , step.eventhandlername , step.configuration , step.SdkMessageProcessingStepId FROM SdkMessageProcessingStep step LEFT JOIN sdkmessagefilter filter ON step.SdkMessageFilterId = filter.SdkMessageFilterId LEFT JOIN entity ON filter.PrimaryObjectTypeCode = entity.ObjectTypeCode WHERE step.IsCustomizable = 1 AND step.ishidden = 0 --and filter.PrimaryObjectTypeCode is not null(不能排除注册在none上的) ORDER BY entity.name , step.sdkmessageidname , step.stage , step.rank , step.SdkMessageProcessingStepId |
- 8. 查询什么角色对指定实体有权限
SELECT * FROM dbo.RoleBase WHERE roleid IN ( SELECT roleid FROM dbo.RolePrivilegesBase WHERE PrivilegeId = ( SELECT PrivilegeId FROM dbo.PrivilegeBase WHERE Name = 'prvReadboc_analyzerassigndisplayprivilege' ) ) |
- 两种虚拟表
--虚拟表(Create Table #temp…insert into #temp…) SELECT businessunitid INTO #temp FROM dbo.GetSubsidiaryBusinesses('9E70F2AD-BC6B-E311-93FB-002481E8832E') SELECT name FROM businessunit WHERE businessunitid IN ( SELECT businessunitid FROM #temp ) --表变量(适合少于10条的数据,不用drop) DECLARE @subBusinessunit TABLE ( businessunitid UNIQUEIDENTIFIER ) INSERT INTO @subBusinessunit SELECT a.businessunitid FROM dbo.GetSubsidiaryBusinesses('9E70F2AD-BC6B-E311-93FB-002481E8832E') a LEFT JOIN businessunit b ON a.businessunitid = b.BusinessUnitId WHERE ( b.new_remarks = 40 OR b.new_remarks = 50 ) SELECT * FROM @subBusinessunit --删除虚拟表: IF EXISTS ( SELECT 1 FROM tempdb..sysobjects WHERE id = OBJECT_ID('tempdb..#t_activity') ) DROP TABLE #t_activity; IF OBJECT_ID('tempdb..#BocDateTime') IS NOT NULL DROP TABLE #BocDateTime |
- 删除和创建索引
IF EXISTS (SELECT name FROM sysindexes WHERE name = 'IDX_Deposits_Metabolic') DROP INDEX IDX_Deposits_Metabolic
ON dbo.CRM_Deposits_SnapShot_Metabolic
CREATE CLUSTERED INDEX IDX_Deposits_Metabolic ON dbo.CRM_Deposits_SnapShot_Metabolic (IsSME, AcctNo) CREATE CLUSTERED INDEX [IX00_Temp_AccountUpdate01] ON [dbo].[Temp_AccountUpdate01]([AccountId] ASC)
|
1) 创建分区函数
CREATE PARTITION FUNCTION [pf_DRKpi](INT) AS RANGE RIGHT FOR VALUES (20120101, 20131230, 20131231, 20140101, 20140102, 20140103, 20140104) 解释: RIGHT:表示右分区,20120101存在右侧分区里面 20120101:边界值 |
2) 创建分区方案
CREATE PARTITION SCHEME [ps_DRKpi] AS PARTITION [pf_DRKpi] TO ([201201], [201201], [201312], [201312], [201401], [201401], [201401], [201401]) 解释: [201201]:存储小于20120101(不含)数据的文件组 [201202] |
3) 创建表(示例)
IF OBJECT_ID('dbo.DRKpi') IS NOT NULL DROP TABLE dbo.DRKpi IF EXISTS (SELECT 1 FROM SYS.partition_schemes WHERE name ='ps_DRKpi') DROP PARTITION SCHEME [ps_DRKpi] IF EXISTS (SELECT 1 FROM sys.partition_functions WHERE name='pf_DRKpi') DROP PARTITION FUNCTION [pf_DRKpi] CREATE PARTITION FUNCTION [pf_DRKpi](int) AS RANGE RIGHT FOR VALUES (20120101) CREATE PARTITION SCHEME [ps_DRKpi] AS PARTITION [pf_DRKpi] TO ([201201],[201201]) begin create table dbo.DRKpi ( SourceDate NVARCHAR(10), --日期 KpiCode NVARCHAR(50), --指标号 KpiName NVARCHAR(200) ,--指标名 [UpdateDate] int not null, [SourceSystem] int not null )ON [ps_DRKpi] ([UpdateDate]) With(Data_compression = Page) CREATE UNIQUE CLUSTERED INDEX [CI_DRKpi] ON [dbo].[DRKpi] ( KpiCode, [UpdateDate] ) end |
- SQL读取数据,填充DataTable,sqlcommand,sqldataadapter 读取超时:ada.SelectCommand.CommandTimeout = 600;以此为例
private DataTable getDataTable(string strSql, string strCon) { DataTable dt = new DataTable(); using (SqlConnection conn = new SqlConnection(strCon)) { conn.Open(); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "usp_QueryBlockTradeInfoByThreadNo"; SqlParameter parThreadNo = new SqlParameter("@ThreadNo", SqlDbType.Int); SqlParameter parMaxThreadNo = new SqlParameter("@MaxThreadNo", SqlDbType.Int); parThreadNo.Value = i; parMaxThreadNo.Value = maxThreadNo; cmd.Parameters.Add(parThreadNo); cmd.Parameters.Add(parMaxThreadNo); try { SqlDataAdapter ada = new SqlDataAdapter(cmd); DataSet dset = new DataSet(); ada.Fill(dset); dt = dset.Tables[0]; } catch { } } } return dt; } |
- 14. 批量插入数据到表
DataTable dt = SqlHelper.ExecuteDataset(connMQCtis, CommandType.StoredProcedure, "").Tables[0]; //插入数据 using (SqlBulkCopy sqlbulk = new SqlBulkCopy(connBOCOCRMReport, SqlBulkCopyOptions.UseInternalTransaction)) { sqlbulk.NotifyAfter = dt.Rows.Count; sqlbulk.DestinationTableName = "dbo.CTIS_TriggerStatis"; foreach (DataColumn col in dt.Columns) { sqlbulk.ColumnMappings.Add(col.ColumnName, col.ColumnName); } sqlbulk.WriteToServer(dt); } |
- 15. 清理活动数据
DECLARE @createdonYear datetime=dateadd(HH,-8,dateadd(year,-1,getdate())) --清理超过1年Task(3个表) --TaskBase(活动实体的自定义字段) --ActivityPartyBase(活动方:表示与某个活动相关联的人员或组,一个活动可以具有多个活动方。) --ActivityPointerBase(活动指针(活动)实体:表示用户已执行或将要执行的任何活动或任务,活动是可在日历上进行输入的任何操作。) WHILE ( 1 = 1 ) BEGIN IF EXISTS ( SELECT 1 FROM tempdb..sysobjects WHERE id = OBJECT_ID('tempdb..#t_taskid') ) DROP TABLE #t_taskid; --查询Task select top 5000 t1.ActivityId into #t_taskid from dbo.TaskBase t1 inner join activitypointerbase t2 on t1.activityid=t2.activityid where t2.CreatedOn<@createdonYear IF ( @@ROWCOUNT <= 0 ) BEGIN BREAK; END BEGIN TRY BEGIN TRANSACTION --删除Task(如果有boc_taskfilter需要先删除) delete from dbo.TaskBase from dbo.TaskBase t1 inner join #t_taskid t2 on t1.ActivityId=t2.ActivityId delete from ActivityPartyBase from ActivityPartyBase t1 inner join #t_taskid t2 on t1.ActivityId=t2.ActivityId --Appointment特需:删除ActivityPointer需要先删除被外键OriginatingActivityId约束的数据 --delete from ActivityPartyBase --from ActivityPartyBase t1 --inner join ActivityPointerBase t2 on t1.ActivityId=t2.ActivityId --inner join #t_appointmentid t3 on t2.[OriginatingActivityId]=t3.ActivityId --delete from ActivityPointerBase --from ActivityPointerBase t1 --inner join #t_appointmentid t2 on t1.[OriginatingActivityId]=t2.ActivityId delete from ActivityPointerBase from ActivityPointerBase t1 inner join #t_taskid t2 on t1.ActivityId=t2.ActivityId COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION; SELECT ERROR_MESSAGE(); BREAK; END CATCH END |
- 16. 获取某用户是否有preReadAccount权限
--获取某用户是否有preReadAccount权限 --注意:RolePrivilegesBase表只存储Top机构的RoleId SELECT COUNT(1) FROM dbo.SystemUserRoles T1 WITH ( NOLOCK ) LEFT JOIN dbo.RoleBase T2 WITH ( NOLOCK ) ON T2.RoleId = T1.RoleId LEFT JOIN dbo.RolePrivilegesBase T3 WITH ( NOLOCK ) ON T3.RoleId = T2.ParentRootRoleId WHERE T3.PrivilegeId = ( SELECT PrivilegeId FROM dbo.PrivilegeBase WITH ( NOLOCK ) WHERE Name = 'prvReadAccount' ) AND T1.SystemUserId = 'FBAA65B8-5B52-E311-9ECD-005056B91CD0' |
ReportSvr:
- 安装SqlServer时未选Reporting Service,后期添加功能,数据库不会创建ReportServer两个DB。需要添加功能之后,进入Reporting Service配置管理工具-数据库-新建。如果报表服务器URL不能访问,进入Web服务Url,点“应用”。
- SqlServer2012安装上CRM出现的报表页面无法访问的问题:Sql安装时选择的帐户无所谓,安装完成报表页面访问出错==>1.services.msc,修改reportingservice的帐户为域顶级账户administrator,重启服务;2.打开reporting services配置管理器,进入“加密密钥”,点击“删除”加密的内容,然后点击“更改”为新的版本。重新访问报表页面。如果CRM报表服务已经安装,需要重新修复一下CRM报表服务。
- 注意。报表做时间类型的比对时,在第一行把时间类型参数dbo.fn_LocalTimeToUTC()转成UTC时间。dbo.fn_UTCToLocalTime()转成本地时间
set @startDate=isnull(@startDate,'1900-01-01')
set @startDate=dbo.fn_LocalTimeToUTC(@startDate)
set @endDate=dbo.fn_LocalTimeToUTC(DATEADD(DD,1,@endDate))
- 修改报表的导出按钮:c\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config
- SSRS10,导出为xls,最大65536行;SSRS11,导出为xlsx,最大行>20W。
- "安装程序无法验证指定的Reporting Services服务器…":原因可能是刚更改了reporting services的登陆用户,需要进入Reporting Services配置管理器-->加密密钥-->删除
- 让报表取到当前表单的ID:
DS1:select new_promotionid from filterednew_promotion as crmaf_filterednew_promotion
DS2:select new_name from filterednew_promotion where new_promotionid=@proid
对DS2生成的参数@proid-属性-默认值-DS1
- 让报表取到当前用户ID:
SELECT [dbo].[fn_FindUserGuid]()
select systemuserid,fullname from FilteredSystemUser where systemuserid = dbo.fn_FindUserGuid()
- 让报表取到当前组织ID:
select businessunitid,name from businessunit where businessunitid = dbo.fn_FindBusinessGuid()
- 参数&必须传%26,但是%26自动被编译为&导致错误,解决:传%2526。编译后仍为%26
- 报表做除法,需要对字段.Value.ToString()
SSIS
1.SSIS调用WCF
1)
WCF中方法需要序列化
2)
WCF的web.config(需要配置webhttpbehavior)
3) SSIS脚本(代理WCF)
[ServiceContract(Name = "IMergeAccount")] public interface IMergeAccount { [WebGet(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IMergerAccountService/Do", ReplyAction = "http://tempuri.org/IMergerAccountService/DoResponse")] void Do(System.Guid userId, System.Guid accountId, System.Guid mergerAccountId); } public class MergeAccountProxy : IMergeAccount { private static ChannelFactory<IMergeAccount> _channelFactory; private static object _lockObj = new object(); public string serviceUrl; public void Do(System.Guid userId, System.Guid accountId, System.Guid mergerAccountId) { if (_channelFactory == null) { lock (_lockObj) { if (_channelFactory == null) { WebHttpBinding binding; Uri address = new Uri(serviceUrl); if (address.Scheme == "https") { binding = new WebHttpBinding(WebHttpSecurityMode.Transport); binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm; } else { binding = new WebHttpBinding(WebHttpSecurityMode.None); } binding.CloseTimeout = new TimeSpan(3, 0, 0); binding.OpenTimeout = new TimeSpan(3, 0, 0); binding.ReceiveTimeout = new TimeSpan(3, 0, 0); binding.SendTimeout = new TimeSpan(3, 0, 0); binding.MaxReceivedMessageSize = 65536000; EndpointAddress endAddress = new EndpointAddress(serviceUrl); ChannelFactory<IMergeAccount> serviceFac = new ChannelFactory<IMergeAccount>(binding, endAddress); serviceFac.Endpoint.Behaviors.Add(new WebHttpBehavior()); _channelFactory = serviceFac; } } } IMergeAccount proxy = _channelFactory.CreateChannel(); try { proxy.Do(userId,accountId,mergerAccountId); ((ICommunicationObject)proxy).Close(); } catch (Exception ex) { try { ((ICommunicationObject)proxy).Abort(); } catch { } throw ex; } } } |
4) SSIS脚本(调用WCF代理)
string vWCF_merge = Dts.Variables["vWCF_merge"].Value.ToString();//http://22.188.136.43:8081/SiteService/WebServices/MergerAccountService.svc/ws MergeAccountProxy dp = new MergeAccountProxy(); dp.serviceUrl = vWCF_merge; dp.Do(new Guid(), Guid.Parse(dr["AccountId"].ToString()), Guid.Parse(dr["MergerAccountId"].ToString())); |
5)
.net & Xml & config:
- 1. 一些方法
1) .net获取两个DateTime的时间差:(DateTime2-DateTime1).TotalSeconds
2)
- .net读取web.config
1.appSettings
<configuration>
<appSettings>
<add key="Email_Host" value="22.188.136.205"/>
</appSettings>
</configuration>
2.添加system.configuration引用
3.using System.configuration
4.取值:ConfigurationManager.AppSettings.Get("Email_Host")
- .net读取.xml[XmlDocument]
private static void InitializeConfig()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C:/CRMExtensionConfig/InoherbCRMExtensionConfig.xml");
XmlNode ConfigNode = xmlDoc.SelectSingleNode("/InoherbCRMExtensionConfig/Inoherb_CustomList");
foreach (XmlNode item in ConfigNode.ChildNodes)
{
switch (item.Name)
{
case "CRMConnectionPath":
CRMConnectionPath = item.InnerText.Trim();
break;
case "CRMSQLConnStr":
CRMSQLConnStr = item.InnerText.Trim();
break;
}
}
}
- Jscript下载文件:
function DownLoadWordFile() {
var url = window.location.protocol + "//" + window.location.hostname + ":8081/SiteService/Web/businesshelp.docx";
window.location.href = url;
}
- 写日志到Windows事件日志:
EventLog myLog = new EventLog();
myLog.Source = "CRM的日志";
myLog.WriteEntry("内容", System.Diagnostics.EventLogEntryType.Information);
- 写日志到文本:
private static void WriteLog(string log)
{
object thislock = new object();
lock (thislock)
{
var logFolder = string.Format("{0}log", AppDomain.CurrentDomain.BaseDirectory);
var logFile = string.Format("{0}\\{1}BlockTradeInfoConsoleLog.txt", logFolder, DateTime.Now.ToString("yyyyMMdd"));
if (!Directory.Exists(logFolder))
{
Directory.CreateDirectory(logFolder);
}
var fs = !File.Exists(logFile) ? File.Create(logFile) : File.Open(logFile, FileMode.Append);
var data = new UTF8Encoding().GetBytes(log);
//开始写入
fs.Write(data, 0, data.Length);
//清空缓冲区
fs.Flush();
//关闭流
fs.Close();
}
}
- 锁定当前方法,串行通过(防止并行调用时出现错误):
private class WriteLog(string log)
{
object thislock = new object();
lock (thislock)
{
//自定义代码
}
}
- SQL语句调用DLL:
EXTERNAL NAME [BOC.GCSPDCRM.SQLCLR].[BOC.GCSPDCRM.SQLCLR.SqlCLRMethod].[GetNewToken]
程序集位置:
- 9. Config.EndPoint
<services> <service name="Trans.WebServices.CrmCommonService"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wshttp" name="wsHttp" contract="Trans.Service.ICrmCommonService" /> <endpoint address="web" binding="webHttpBinding" bindingConfiguration="webhttpjsonp" name="webHttp" contract="Trans.Service.ICrmCommonService" behaviorConfiguration="webhttpbehavior" /> </service> </services>
|
/// <summary> /// 获取CRMWeb下web.config中数据库连接信息 /// </summary> /// <param name="strDataPath">数据库地址节点</param> /// <returns></returns> public string GetCrmDataUrl(string strDataPath) { string strCrmDataUrl = ""; if (strDataPath != "") { RegistryKey rsg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM"); string strPath = null; if (rsg != null && rsg.GetValue("WebSitePath") != null) { strPath = rsg.GetValue("WebSitePath").ToString(); } //配置文件路径 string dir = strPath + "\\web.config"; try { var xmlDoc = new XmlDocument(); xmlDoc.Load(dir); XDocument doc = XDocument.Parse(xmlDoc.InnerXml); IEnumerable<XElement> nameElements = doc.Root.Element("connectionStrings").Elements("add"); foreach (XElement nameElement in nameElements) { if (nameElement.FirstAttribute.Value == strDataPath) { strCrmDataUrl = nameElement.FirstAttribute.NextAttribute.Value; } } } catch (Exception ex) { throw new Exception("获取数据库连接失败"); } } return strCrmDataUrl; } |
- 桥接网卡
- 映射网络驱动器:\\vboxsvr\E_DRIVE
- 1. SSRS,前端,异步服务分多服务器安装
VMBox
CRM安装
1)
- 服务器1:域 + SqlServer + (CRM Reporting Extensions +CRM Srs Rollup)
- 服务器2:CRM前端服务器(create new) + CRM Server Rollup
- 服务器3:CRM完全服务器 + CRM Server Rollup
好处:服务器3上的异步可以方便的调用本机的WCF服务,而不影响服务器2 - Crm2011安装前必须组件一览(“Microsoft应用程序错误报告”已自带)
- 遇到过的错误
1)
2015.3.5:安装en_WinSvr2008R2+en_SqlServer2012+en_Crm2011,安装Crm2011的时候,输入序列号后就提示安装vcredist_x64.exe失败,手动安装,提示系统已经有更新版本。
解决:en_Crm2011版本过低,无法和en_SqlServer2012兼容,重新下载了更新版的en_Crm2011(自带Rollup6)就可以。
2)
同上系统,在SQL服务器上安装CRM reporting extension一直报错。
解决:SQL安装包问题,安装SQL的时候勾选更新即可。
3)
The SQL Server Reporting Services account is a local user and is not
supported.
解决:在报表管理器里面,修改帐户为Local Service或者域用户,重新运行CRM Reporting Extensions安装程序。
4)
Check SqlServerAgentValidator : Failure: SQLSERVERAGENT
(SQLSERVERAGENT) service is not running on the server ***.
原因:安装CRM的用户没有Sql服务器的本地管理员权限
处理:
- 把安装CRM的用户添加到Sql服务器的本地管理员组中
- 把此用户添加到SqlServer-安全性-登录名中,给sysadmin角色。
5) 20150612黑山扈投产演练遇到5个问题:
- CRM安装用户需要对CRM安装时选择的组织有全部继承的权限
- 检查报表数据库是否已正确安装
- CRM Reporting Extension需要装在所有数据集群机器上,否则新建CRM组织时检测报没有安装crm reporting extension
- CRM安装时选来用做初始化服务的帐户不能添加为CRM用户,会导致CRM组织崩溃(需通过重建CRM组织解决)
https://support.microsoft.com/en-us/kb/2500917 - 本机不能用https访问本机安装的https站点。
6)
安装完成CRM之后,IE打开报错:UserId或域用户不可用
现象:用自定义用户初始化安装的CRM
处理:用CRM的初始化用户登陆系统,打开IE访问。
- 4. Windows Server 2012安装CRM2011
1) 安装Sql Server2012需要先从“添加角色”中安装.net framework3.5
2) 缺少的Windows Identity Foundation可从“添加角色”中自行安装。
3) 安装CRM2011报缺少.net Framework4.0可通过setup update(Server_KB2434455_amd64_1033.msp)包来解决。
4) Server 2012 安装CRM必须提前手动安装好IIS,系统不自带
5) Server 2012 R2 不能安装CRM2011
6) 更改系统序列号:slui.exe 0x3
- 5. 安装后遇到的问题
1)
安装成功,报表无法查看,“参数无效”:
Web service request
SetDataSourceCredentials to Report Server http://win-svr/ReportServer failed
with SoapException. Error: 处理报表时出错。 (rsProcessingAborted)
- 1.服务账户 + (数据库-当前报表服务器数据凭证),都用域账户
- 2.加密密钥 - 更改
- 3.修复CRM Reporting Extensions
2)
安装成功,WCF访问出:未能加载“System.SystemModel.dll”中的“System.SystemModel.Activation.HttpModel”。。
解决方法:C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe
-iru
- 配置HTTPS:
1) IIS-服务器证书-导入证书(证书颁发者也需要)
2) 站点-添加绑定HTTPS-选中证书
3)
CRM Deployment Manager – 修改 web address 为 https,修改服务路径
4) 客户机安装根证书-访问
- 域和证书服务不可以同时安装:将本机升级为域控时,会提示已经安装了证书服务,必须先删除。
- 产品密钥与安装的Microsoft Dynamics CRM版本不兼容
http://blog.csdn.net/jxian2009/article/details/39180709
在服务器2,点击“开始”,运行“regedit”,找到如下路径:“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM”,如果没有“MSCRM”,则对项“Microsoft”点击右键,新建该子项。对项“MSCRM”点击右键,新建“DWORD(32-位)值”,输入“IgnoreChecks”。双击“IgnoreChecks”,修改值为“1”。
1) 安装报错,LicenseAction….处理方法:卸载服务器1的rollup,再进行安装。
- 新建或导入组织失败:没有安装CRM Reporting
Extensions。但是服务器已经安装了。
检查regedit:CRM_SrsDataConnector_InstallDir。
10.CRM重装,最好把相关注册表清空。
其他:
- 多用户同时远程:gpedit.msc (gpupdate /force)
a) 计算机配置-管理模版-Windows 组件-远程桌面服务-远程桌面会话主机-连接
i. 将远程桌面服务限制到单独的会话-禁用(可以两人同时远程了)
ii. 拒绝将已登录会话的管理员注销-启用(不可以强制踢出活动远程)
b) 添加角色和功能-远程桌面服务-远程协助-远程桌面会话主机(可以无限制同时远程了)
- 用Lambda表达式代替callback回调函数:
Helper.QueryAccounts("张三", (accounts) => { If(accounts.count>0){ Helper.DeleteAccount(…); } }); Private void QueryAccounts(string name,Action<EntityCollection> callback){...} |
- windows server 2008实现多用户同一用户名同时登陆
控制面板-管理工具-终端管理-终端管理Host配置-限制每个用户只能使用一个会话,勾去掉。 - DOS:
a) 隐藏文件夹attrib +s +h e:/123
b) 取消隐藏attrib -s -h e:/123
- Google搜索:
“你要搜的内容”-inurl:(htm|html|php|pls|txt) intitle:index.of “last modified” (mkv|mp4|avi) - Console.exe直接点击执行,读取的配置是*.exe.config,不是app.config或web.config
- 远程重启IIS
iisreset \\192.168..
shutdown \\.. - 任务计划程序,运行时不显示CMD框:勾选“不管用户是否登陆都要运行”。
菜单Menu
- 菜单关联视图:<SubArea Id="yto_yto_applytogoods_dqr" Title="待确认的要货申请" Icon="/_imgs/ico_16_customEntity.gif" Url=“/_root/homepage.aspx?etn=<entity logical name >&viewid=%7b<GUID value of view id>%7d”></SubArea>
按钮Button
- 用Ribbon Editor给自定义按钮添加JS事件:Library($webresource:web资源的名称)
- 活动实体的Homepage按钮,是受实体“活动”的Homepage按钮控制的,Form和Sub_grid的按钮则是自己控制的。
- 隐藏按钮:(也可隐藏tab:Related)
<HideCustomAction Location="Mscrm.HomepageGrid.boc_financialalertsetting.RunReport" HideActionId="Mscrm.HomepageGrid.boc_financialalertsetting.RunReport.HideAction" />
- JS隐藏按钮:
parent.document.getElementById("boc_financialalertprocess|NoRelationship|Form|Mscrm.Form.boc_financialalertprocess.MainTab.CustomGroup").style.display = "none";
遇到的问题:如果把隐藏按钮JS放在FormOnload上:点击Form左侧导航,再回到Form时Ribbon会重新加载,而Form上的JS不会加载,导致隐藏无效。
解决:可以放到按钮的enabled自定义事件中来隐藏。
//分发按钮.显示 function boc_taskmanagerFormOnLoad_1() { var formType = Xrm.Page.ui.getFormType(); var ret = false; var btn = parent.document.getElementById("boc_taskmanager|NoRelationship|Form|Boc.Form.boc_taskmanager.MainTab.Save.Distribute-Large"); btn.style.display = "none"; var boc_issent = Xrm.Page.getAttribute("boc_issent").getValue(); if (formType == 2 && !boc_issent) { btn.style.display = ""; ret = true; } return ret; } |
- 按钮图片:
Image16by16="$webresource:avanade_/Images/Submit32.png" Image32by32="$webresource:avanade_/Images/Submit32.png"
Image16by16="/_imgs/ribbon/ImportData_16.png" Image32by32="/_imgs/ribbon/importdata32.png"
- 按钮:"下载用于导入的模版”:
模板上的列等于实体表单Form上的所有字段。
按钮转到url,url里面不能带参数,用StringParameter传递参数。("../"因为在IE8,URL会自动添加_root变成"_root/tools/…")
- 修改报表的导出按钮:c\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config SSRS10,导出为xls,最大65536行;SSRS11,导出为xlsx,最大行>20W。
- 通过“应用程序功能区”操作全局按钮(见CRM_Ribbon文件夹):
<HideCustomAction Location="Mscrm.HomepageGrid.{!EntityLogicalName}.MainTab.Collaborate" HideActionId="Mscrm.HomepageGrid.{!EntityLogicalName}.MainTab.Collaborate.HideAction" />
Crm2011\CRM_JS
sdk.soap.js:参数中有callback的,如果为null,则为同步,用var res=Fuc的方式接收;否则传callback,为异步。
sdk.rest.js:可以通过req.open()的最后一个参数,自定义是否异步或者同步:true,异步;false,同步。
sdk.js:已经压缩过的sdk,包含soap和rest。
REST:
JS查询(查询条件是中文需要转符encodeURI()/encodeURIComponent(),可关联查询expand是关系名称)
SDK.REST.retrieveRecord(Xrm.Page.context.getUserId(), "SystemUser", "BusinessUnitId,business_unit_system_users/boc_originaldivisionname", "business_unit_system_users",
function success(res) {
if (res.BusinessUnitId.Id != null) {
var objList = new Array();
var obj = new Object();
obj.id = res.BusinessUnitId.Id;
obj.name = res.BusinessUnitId.Name;
obj.typename = res.BusinessUnitId.LogicalName;
objList[0] = obj;
Xrm.Page.getAttribute("boc_businessunitid").setValue(objList);
Xrm.Page.getAttribute("boc_businessunitid").setSubmitMode("always");
}
},
function error(res) {
alert(res.message);
}, false);
var entity = new Object;
entity.boc_issetted = bool;
SDK.REST.updateRecord(ids[i], entity, "boc_comparisonItemsetting",
function (res) { },
function (res) { });
REST.BUG
1.关联查询时,虽然在oData中指定了只查询(business_unit_system_users/boc_originaldivisionname),但在CRM向数据库查询的SQL中,是查询了businessunit的所有字段的。
SOAP:
同步调用:
var res = SDK.Soap.RetrieveEntityMetadata("", "boc_financialalertsetting", false,null);
alert("RES:" + res[0].ObjectTypeCode);
异步调用:
SDK.Soap.RetrieveEntityMetadata("", "boc_financialalertsetting", false, function (r) {
alert("R:"+r[0].ObjectTypeCode);
});
SDK.Soap.Associate("boc_boc_areazoomtable_account", "account", PrimaryItemIds, "boc_areazoomtable", res.items, null)
SDK.Soap.Fetch("<fetch mapping='logical' count='50' aggregate='true' version='1.0'><entity name='boc_systemnotification'><attribute name='activityid' aggregate='count' alias='count' /><filter><condition attribute='boc_systemnotificationstate' operator='eq' value='0' /><condition attribute='ownerid' operator='eq' value='" + userId + "' /></filter></entity></fetch>",
false,
function (res) {
alert("您有" + res[0].attributes.count.value + "条未读通知提醒.")
});
多对多查询(根据用户名查询角色名):
<fetch mapping="logical" count="50" version="1.0"> <entity name="role"> <attribute name="name" /> <link-entity name="systemuserroles" from="roleid" to="roleid"> <link-entity name="systemuser" from="systemuserid" to="systemuserid"> <filter> <condition attribute="fullname" operator="like" value="1一般用户01" /> </filter> </link-entity> </link-entity> </entity> </fetch> |
JS.Fun
- 超过6个subgrid不会自动显示数据(onload,参数100)
//刷新MS CRM表单中未自动加载的SubGrid
var refreshSubGridId;
function loadSubGrids(milliSeconds) {
if (!milliSeconds) milliSeconds = 1000;
refreshSubGridId = setInterval(refreshSubGrids, milliSeconds);
}
function refreshSubGrids() {
var blnSuccess = false;
try {
var subgrids = Xrm.Page.ui.controls.get(function (control, index) { return control.getControlType() == "subgrid"; });
if (subgrids.length > 4) for (var i = 4; i < subgrids.length; i++) subgrids[i].refresh();
blnSuccess = true;
} catch (e) { }
if (blnSuccess) clearInterval(refreshSubGridId);
}
- 禁用SubGrid
function disableSubGrid(subGridName) {
try {
var subGrid = document.getElementById(subGridName + "_span");
if (subGrid) subGrid.disabled = true;
} catch (e) { }
}
- 转REST获取的日期类型(从“/Date***”到“Fri Nov 1 00:00:00 UTC+0800 2013”)
function dateReviver(value) {
var a;
if (typeof value === 'string') {
a = /Date\(([-+]?\d+)\)/.exec(value);
if (a) {
return new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10));
}
}
return value;
};
- JS返回日期间隔
function dateDiff(interval, date1, date2)
{
var objInterval = {'D' : 1000 * 60 * 60 * 24, 'H' : 1000 * 60 * 60, 'M' : 1000 * 60, 'S' : 1000, 'T' : 1};
interval = interval.toUpperCase();
var dt1 = Date.parse(date1.replace(/-/g, '/'));
var dt2 = Date.parse(date2.replace(/-/g, '/'));
try
{
return Math.round((dt2 - dt1) / eval('(objInterval.' + interval + ')'));
}
catch (e)
{
return e.message;
}
}
说明:interval 取值: d (day), m(minutes), s(second), t(毫秒),不分区大小写
日期格式: yyyy (/-) (m)m (/-) (d)d
- 调用流程-脚本:
SystemUserChangeSignerAction = function (objectId) {
var url = Boc.Utility.ServerUtility.GetUrl() + "cs/dialog/rundialog.aspx?DialogId=%7b1889E36D-F08C-4259-B714-1DAE5A5E6028%7d&EntityName=systemuser" + "&ObjectId=" + objectId;
window.showModalDialog(url, "", "dialogWidth=600px;dialogHeight=400px");
parent.location.href = parent.location.href;
//parent.close();
};
插件操作
通过Fetch查询
- //根据客户ID获取客户类型
private int GetAccounttypeById(Guid accountId, IOrganizationService service)
{
int yto_accounttype = 0;
string fetchxml = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='account'>
<attribute name='new_payment_method' />
<filter type='and'>
<condition attribute='statecode' operator='eq' value='0' />
<condition attribute='accountid' operator='eq' value='" + accountId + @"' />
</filter>
</entity>
</fetch>";
EntityCollection entityCollection = service.RetrieveMultiple(new FetchExpression(fetchxml));
foreach (var entity in entityCollection.Entities)
{
if (entity.Contains("yto_accounttype"))
{
yto_accounttype = (entity["yto_accounttype"] as OptionSetValue).Value;
}
}
return yto_accounttype;
}
*item.FormattedValues["new_payment_method"],可以取到下拉列表的显示值。
*fetchXML查询的分组和统计
<fetch distinct='false' mapping='logical' aggregate='true'>
<attribute name='new_amount' alias='new_amount_sum' aggregate='sum' />
<attribute name='new_bugetid' groupby='true' alias='new_bugetid_all' />
*取数量 returntotalrecordcount="true"
取值
(((AliasedValue)item["new_bugetid_all"]).Value as EntityReference)
取主表单上的字段:(用别名alias)
<attribute name='new_name' alias='new_name_m'/>
连接CRM服务器
外部方式:
using System;
using Microsoft.Xrm.Client;
/// <summary>
/// 初始化CRM服务
/// </summary>
/// <param name="org">组织名</param>
/// <returns></returns>
private static OrganizationServiceProxy GetCrmService(string org)
{
try
{
org = org.ToLower();
//CRM服务地址
var crmUrlKey = string.Format("{0}_serverurl", org);
//CRM登录域名
var userdominKey = string.Format("{0}_userdomin", org);
//CRM登录用户名
var usernameKey = string.Format("{0}_username", org);
//CRM登录密码
var userpasswordKey = string.Format("{0}_userpassword", org);
//初始化CRM服务凭证
var clientCredentials = new ClientCredentials();
clientCredentials.Windows.ClientCredential.Domain = ConfigurationManager.AppSettings[userdominKey];
clientCredentials.Windows.ClientCredential.UserName = ConfigurationManager.AppSettings[usernameKey];
clientCredentials.Windows.ClientCredential.Password = ConfigurationManager.AppSettings[userpasswordKey];
//初始化服务
var service = new OrganizationServiceProxy(new Uri(ConfigurationManager.AppSettings[crmUrlKey]), null, clientCredentials, null)
{
Timeout = new TimeSpan(12, 0, 0)
};
service.ServiceChannel.Open();
return service;
}
catch (Exception ex)
{
throw new Exception("初始化CRM服务失败:" + ex.Message);
}
}
插件方式:
using System;
using Microsoft.Xrm.Sdk;
namespace TestCreateAccount
{
public class Class1:IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// 初始化context
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// 初始化tracingService
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// 初始化orgService
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
IOrganizationService serviceSys = serviceFactory.CreateOrganizationService(null);
}
}
}
互转:FetchXml和QueryExpression
- SDK方法:转QueryExpression为FetchXml
public string Convert(QueryExpression queryExpression)
{
QueryExpressionToFetchXmlRequest request = new QueryExpressionToFetchXmlRequest();
request.Query = queryExpression;
var response = (QueryExpressionToFetchXmlResponse)orgService.Execute(request);
return response.FetchXml;
}
- SDK方法:转FetchXml为QueryExpression
public QueryExpression Convert(string strFetchXml)
{
FetchXmlToQueryExpressionRequest request = new FetchXmlToQueryExpressionRequest();
request.FetchXml = strFetchXml;
var response= (FetchXmlToQueryExpressionResponse)orgService.Execute(request);
response.Query.NoLock = true;
return response.Query;
}
获取topContext
/// <summary>
/// 获取最顶级插件上下文对象
/// </summary>
/// <param name="currentContext">当前插件上下文对象</param>
/// <returns>返回最顶级插件上下文对象</returns>
public IPluginExecutionContext GetTopContext(IPluginExecutionContext currentContext)
{
IPluginExecutionContext topContext = currentContext;
for (int i = 0; i <= currentContext.Depth; i++)
{
if (topContext.ParentContext!=null)
{
topContext = topContext.ParentContext;
}
}
return topContext;
}
获取日期间隔
DateTime DateTime1 = new DateTime(2015, 2, 1, 10, 10, 10); DateTime DateTime2 = new DateTime(2015, 3, 1, 10, 11, 10); string dateDiff = null; TimeSpan ts = DateTime2 – DateTime2; dateDiff = ts.Days.ToString() + "天" + ts.Hours.ToString() + "小时" + ts.Minutes.ToString() + "分钟" + ts.Seconds.ToString() + "秒"; 以秒展示间隔:ts.TotalSeconds; |
写入日志
#region 写入系统日志 private static void WriteLog(string msg, EventLogEntryType eventType) { EventLog myLog = new EventLog(); myLog.Source = "导入大额交易"; myLog.WriteEntry(msg, eventType); } #endregion #region 写入文件日志 private static void WriteLog(string log) { try { object thislock = new object(); lock (thislock) { var logFolder = string.Format("{0}log", AppDomain.CurrentDomain.BaseDirectory); var logFile = string.Format("{0}\\{1}.txt", logFolder, DateTime.Now.ToString("yyyyMMdd")); if (!Directory.Exists(logFolder)) { Directory.CreateDirectory(logFolder); } var fs = !File.Exists(logFile) ? File.Create(logFile) : File.Open(logFile, FileMode.Append); var data = new UTF8Encoding().GetBytes(log); //开始写入 fs.Write(data, 0, data.Length); //清空缓冲区 fs.Flush(); //关闭流 fs.Close(); } } catch (Exception ex) { WriteLog(log); } } /// <summary> /// 删除前一天日至文件 /// </summary> private static void DeleteYestLog() { var logFolder = string.Format("{0}log", AppDomain.CurrentDomain.BaseDirectory); var logFile = string.Format("{0}\\{1}.txt", logFolder, DateTime.Now.AddDays(-1).ToString("yyyyMMdd")); if (File.Exists(logFile)) { File.Delete(logFile); } } #endregion |
读取csv
FileStream fs = new FileStream("update.csv", FileMode.Open, FileAccess.Read, FileShare.None); StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8); while (true) { string line = sr.ReadLine(); if (line == null) { break; } string[] value = line.Split(','); Guid businessunitid = Guid.Parse(value[0]); Guid parentid = Guid.Parse(value[1]); } sr.Close(); |
C#事务
/* * 参数1:TransactionOptions模式 * Required 如果已经存在一个事务,那么这个事务范围将加入已有的事务。否则,它将创建自己的事务。 * RequiresNew 这个事务范围将创建自己的事务。 * Suppress 如果处于当前活动事务范围内,那么这个事务范围既不会加入氛围事务 (ambient transaction),也不会创建自己的事务。 * 当部分代码需要留在事务外部时,可以使用该选项。 * 参数2:设置超时间隔,默认为60秒 */ using (TransactionScope tranScope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 2, 0))) { string conn = ""; SqlHelper.ExecuteNonQuery(conn, CommandType.Text, ""); SqlHelper.ExecuteNonQuery(conn, CommandType.Text, ""); //提交事务 tranScope.Complete(); } |
字段操作
1.LookUp
给Lookup取值赋值:
id:obj.getValue()[0].id;
name:obj.getValue()[0].name;
type:obj.getValue(){0}.type;
typename:obj.getValue()[0].typename;
货币符号:obj.getValue()[0].keyValues["currencysymbol”].value;
注意:keyValues在表单onload时是没有这些值的,onchange时有。
document.getElementById(cptFieldName + "_sym").innerText = “$”;
var objList = new Array();
var obj = new Object();
obj.id = accountObj[0].TerritoryId.Id;
obj.name = accountObj[0].TerritoryId.Name;
obj.typename = accountObj[0].TerritoryId.LogicalName;
objList[0] = obj;
Xrm.Page.getAttribute("yto_territory").setValue(accountObj[0].TerritoryId.Id == null ? null : objList);
Xrm.Page.getAttribute("yto_territory").setSubmitMode("always");
Xrm.Page.data.entity.save();
给Lookup添加过滤:(处理列对不齐:icon="0" preview="0")
var fetch = '';
var view = '';
Xrm.Page.getControl("new_detailitem").addCustomView("{B9C6A1F4-0A03-424D-B843-E4D9281F8DEB}", "new_expensesdetail", "根据部门和费用期间筛选", fetch, view, true);
document.getElementById("new_detailitem").setAttribute("disableViewPicker", "1");
A.取fetchxml和viewxml:
高级查找-编辑列-F12-脚/dlg_editview.aspx
frameRender.FetchXml.value
frameRender.LayoutXml.value
B.addCustomView("如果使用已存在视图的GUID,会借用已存在视图名称","过滤的实体名称","自定义过滤视图名称",fetchxml,viewxml,是否默认视图)
Lookup记录选择窗口完全自定义方式
var typeCode = Mscrm.EntityPropUtil.EntityTypeName2CodeMap.boc_tradezoomtable;
var lookupViewArgs = {
items: null,
customViews: [{
id: "{F86239AE-C483-E211-B9C3-00155D332305}",
recordType: typeCode,
name: "可选的情景分析行业优先次序表",
fetchXml: '',
layoutXml: '',
Type: 0
}],
availableViews: null
};
var url = "/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultViewId=%7bF86239AE-C483-E211-B9C3-00155D332305%7d&DisableQuickFind=0&DisableViewPicker=1&ShowNewButton=1&ShowPropButton=1&LookupStyle=multi&browse=0&objecttypes=" + typeCode;
var res = openStdDlg(Xrm.Page.context.prependOrgName(url), lookupViewArgs, 620, 690);
if (res && res.items && res.items[0]) {
try {
SDK.Soap.Associate("boc_boc_tradezoomtable_account", "account", PrimaryItemIds, "boc_tradezoomtable", res.items, null)
} catch (e) {
if (e.message == "Cannot insert duplicate key.") {
alert("关联已存在!");
} else {
alert(e.message);
}
}
Mscrm.Utilities.refreshCurrentGrid(typeCode);
}
[LookupStyle:multi/single.0:false;1:true.可快速查找的列,通过快速查找视图配置]
多选查找,多选Lookup,自定义LookUp操作
function boc_serviceteamSubgridAddLocalUser() { var url = '/' + Xrm.Page.context.getOrgUniqueName() + '/_controls/lookup/lookupinfo.aspx?LookupStyle=multi&browse=0&objecttypes=8'; var selected = window.showModalDialog(url, null, "dialogWidth=600px;dialogHeight=700px"); if (typeof (selected) != "undefined") { var lookups = $.parseJSON(selected); var urlStr = window.location.protocol + "//" + window.location.hostname + ":8082/OverSeaWeb/WebServices/CustomPageService.svc/OverseaAddServiceTeam"; var index = 0; $.each(lookups.items, function (i, v) { $.ajax({ type: 'GET', url: urlStr, data: { "etn": Xrm.Page.data.entity.getEntityName(), "userid": v.id, "userorg": "APAC", "accountid": Xrm.Page.data.entity.getId(), "accountorg": "APAC" }, dataType: "JSONP", async: false, success: function (data) { //var contentObj = $.parseJSON(data); //if (contentObj != null && contentObj != "") { //} //else { // errorInfo = "error"; //} index++; if (index == lookups.items.length) Xrm.Page.getControl('serviceteam').refresh(); }, failure: function (error) { //alert("failure"); index++; }, complete: function (result) { //alert("complete"); } }); }); } } |
2.OptionSet
给OptionSet按条件显示列:
Xrm.Page.getControl("new_counter_type").clearOptions();
var options = Xrm.Page.getAttribute("new_counter_type").getOptions();
var index=0;
for (var i = 0; i < options.length; i++) {
if (options[i].value != 190 && options[i].value != 200 && options[i].value!="null" ) {
Xrm.Page.getControl("new_counter_type").addOption(options[i], index);
index++;
}
}
Xrm.Page.getControl("new_counter_type").addOption(Xrm.Page.getAttribute("new_counter_type").getOption(190),1);
var entity = new Object;
entity.boc_status = new Object;
entity.boc_status.Value = 2;
REST:
var value=res.boc_type.Value.
3.DateTime
1.SQL取,WCF创建或更新。SQL取的时候需要+8H(生成时间操作者的时差),因为WCF处理到数据库时会-8H。
2.同样:WCF取,SQL创建或更新。SQL需要-8H,因为WCF取的时候会+8H。
3.如果存在用户处于不同的时差设置,则不可以+8或者-8。需要SQL取,SQL更新;或者WCF取,WCF更新(但要确保WCF的初始化用户有相同的时差,否则,可以通过WCF更新后,再通过SQL单独更新一下时间字段)
4. WCF取,WCF创建或更新(初始化用户处于相同时区);SQL取,SQL创建或更新,没问题。
给日期类型控件赋值:
var fullYear = Xrm.Page.getAttribute("yto_confirmdate").getValue().getFullYear();
var month = Xrm.Page.getAttribute("yto_confirmdate").getValue().getMonth() + 1;
var date = Xrm.Page.getAttribute("yto_confirmdate").getValue().getDate();
Xrm.Page.getAttribute("yto_confirmdate").setValue(new Date(fullYear, month, date))//厂方确认交货日期+1月
赋当前值:
Xrm.Page.getAttribute("boc_managermodifiedon").setValue(new Date());
日期比较:
var boc_begintime = Xrm.Page.getAttribute("boc_begintime").getValue();
var boc_endtime = Xrm.Page.getAttribute("boc_endtime").getValue();
var boc_now = (new Date()).format("yyyyMMdd");
if (boc_begintime != null && boc_endtime != null && boc_begintime.format("yyyyMMdd") >= boc_endtime.format("yyyyMMdd")) {
var alertStr = "The end time must be greater than the start time !";
alert(alertStr);
eContext.getEventSource().setValue(null);
}
常用SQL
1.获取所有下级用户(根据boc_mamagerid)
IF EXISTS ( SELECT * FROM tempdb..sysobjects WHERE id = OBJECT_ID('tempdb..#t_subordinate') ) DROP TABLE #t_subordinate; WITH cp_usubordinate AS ( SELECT u.SystemUserId , u.boc_manager , 1 AS depth FROM systemuser u WITH ( NOLOCK ) WHERE u.systemuserid = '5F5AB66A-0742-E211-B430-005056B91CD0' UNION ALL SELECT subU.systemuserid , subU.boc_manager , depth + 1 FROM cp_usubordinate , systemuser subU WITH ( NOLOCK ) WHERE cp_usubordinate.systemuserid = subU.boc_manager ) SELECT * --INTO #t_subordinate FROM cp_usubordinate |
2.获取所有下级部门(根据ParentBusinessUnitId)
IF EXISTS ( SELECT * FROM tempdb..sysobjects WHERE id = OBJECT_ID('tempdb..#t_bu') ) DROP TABLE #t_bu; WITH cp_bu AS ( SELECT bu.BusinessUnitId , 1 AS depth FROM systemuser u WITH ( NOLOCK ) INNER JOIN BusinessUnit bu ON bu.businessunitid = u.BusinessUnitId WHERE u.systemuserid = 'F9EDC085-D4FF-E211-8F5A-005056B91CD0' UNION ALL SELECT subB.BusinessUnitId, depth + 1 FROM cp_bu , BusinessUnit subB WITH ( NOLOCK ) WHERE cp_bu.BusinessUnitId = subB.ParentBusinessUnitId ) SELECT * --INTO #t_bu FROM cp_bu; |
3.返回goal全都等于指定值的Name
--需求:返回goal全都相等的Name DECLARE @t TABLE(NAME NVARCHAR(10),goal INT) INSERT INTO @t VALUES('a',1) INSERT INTO @t VALUES('a',2) INSERT INTO @t VALUES('b',2) INSERT INTO @t VALUES('b',2) INSERT INTO @t VALUES('c',1) INSERT INTO @t VALUES('c',3) --针对返回单个字段name ;WITH T1 AS ( SELECT name ,MAX(goal) mag ,MIN(goal) mig FROM @t GROUP BY name) SELECT name FROM t1 WHERE mag=mig AND mag=2 --针对返回多个字段name,age(使用分区) ;WITH T2 AS ( SELECT name ,age ,goal , MAX(goal) OVER(PARTITION BY name) as maxg,MIN(goal) OVER(PARTITION BY name) ming FROM @t) SELECT name,age,goal FROM T2 WHERE maxg=ming and ming=2 |
4.顺序合并,必须先5到4,再4到3...,如果出现3到5,则报错
--需求:合并,必须先5到4,再4到3...,如果出现3到5,则报错 DECLARE @T TABLE (n1 INT,n2 INT) INSERT INTO @T VALUES(1,2) INSERT INTO @T VALUES(4,5) INSERT INTO @T VALUES(2,3) INSERT INTO @T VALUES(3,4) --SELECT * FROM @T ;WITH T1 AS ( SELECT n1,n2,0 AS Lv FROM @T UNION ALL SELECT T2.n1,T2.n2,T1.Lv+1 FROM @T T2 INNER JOIN T1 ON T1.n2=T2.n1) SELECT n1,n2 FROM T1 GROUP BY n1,n2 ORDER BY MAX(Lv) DESC |
5.获取部门和其子部门下所有用户,包括用户部门和角色
WITH CategoryInfo AS ( SELECT BusinessUnitId , Name FROM BusinessUnit WITH ( NOLOCK ) WHERE BusinessUnitId = '13FD7D12-F941-E211-B430-005056B91CD0' UNION ALL SELECT BU.BusinessUnitId , BU.Name FROM BusinessUnit AS BU WITH ( NOLOCK ) INNER JOIN CategoryInfo AS CI ON BU.ParentBusinessUnitId = CI.BusinessUnitId ) SELECT CF.BusinessUnitId , CF.Name AS businessunitName , SU.FullName AS SystemUserName , SU.SystemUserId , RUser.Name AS roleName FROM CategoryInfo CF WITH ( NOLOCK ) INNER JOIN SystemUser SU WITH ( NOLOCK ) ON CF.BusinessUnitId = SU.BusinessUnitId INNER JOIN ( SELECT R.Name , SR.SystemUserId , SR.RoleId FROM Role R WITH ( NOLOCK ) INNER JOIN SystemUserRoles SR WITH ( NOLOCK ) ON R.RoleId = SR.RoleId ) RUser ON RUser.SystemUserId = SU.SystemUserId WHERE SU.IsDisabled = 0 ORDER BY SU.SystemUserId; |
6.获取部门和其子部门下所有团队,包括团队部门和角色
WITH CategoryInfo AS ( SELECT BusinessUnitId , Name FROM BusinessUnit WITH ( NOLOCK ) WHERE BusinessUnitId = '{0}' UNION ALL SELECT BU.BusinessUnitId , BU.Name FROM BusinessUnit AS BU WITH ( NOLOCK ) INNER JOIN CategoryInfo AS CI ON BU.ParentBusinessUnitId = CI.BusinessUnitId ) SELECT CF.BusinessUnitId , CF.Name AS businessunitName , TM.Name AS teamName , TM.TeamId , RTeam.Name AS roleName , RTeam.RoleId FROM CategoryInfo CF WITH ( NOLOCK ) INNER JOIN Team TM WITH ( NOLOCK ) ON CF.BusinessUnitId = TM.BusinessUnitId INNER JOIN ( SELECT R.Name , TR.TeamId , TR.RoleId FROM Role R WITH ( NOLOCK ) INNER JOIN TeamRoles TR WITH ( NOLOCK ) ON R.RoleId = TR.RoleId ) RTeam ON RTeam.TeamId = TM.TeamId ORDER BY TM.TeamId; |
7.SQL备份数据库(每周全备、每日差备)
--exec usp_Backup 'BackupTest', 'D:\test', 'Full' CREATE procedure [dbo].[usp_Backup] (@db_name nvarchar(100), @back_dir nvarchar(2000), @type nvarchar(20)) as begin declare @begintime datetime = getdate(); declare @weekday int = datepart(weekday, @begintime); declare @businessday int = FORMAT(@begintime,'yyyyMMdd'); declare @sql nvarchar(4000) = '' declare @filename nvarchar(500) = @db_name + '_' + @type + '_' + convert(nvarchar(1), @weekday) declare @file nvarchar(2000) = @back_dir + '\' + @filename + '.bak'; BEGIN TRY if exists(select 1 from [dbo].[BackupLog] where [DBName] = @db_name and [BackupType] = @type and [BusinessDay] = @businessday) BEGIN --已存在 RETURN end if not exists(select 1 from [dbo].[BackupLog] where [DBName] = @db_name and [BackupType] = 'Full') BEGIN --须先做全备 SET @type = 'Full' end if(@type = 'Full') BEGIN --全备 SET @sql = ' BACKUP DATABASE [' + @db_name + '] TO DISK = N''' + @file + ''' WITH NOFORMAT, INIT, NAME = N''' + @filename + '_' + convert(nvarchar(10), @businessday) + ''', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 10' --print @sql exec(@sql) end if(@type = 'Diff') BEGIN --差备 SET @sql = ' BACKUP DATABASE [' + @db_name + '] TO DISK = N''' + @file + ''' WITH DIFFERENTIAL , NOFORMAT, INIT, NAME = N''' + @filename + '_' + convert(nvarchar(10), @businessday) + ''', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 10' --print @sql exec(@sql) end --记录备份 if (@type in ('Full', 'Diff')) INSERT INTO [dbo].[BackupLog] ([DBName] ,[BackupDir] ,[BackupFile] ,[BackupType] ,[BeginTime] ,[EndTime] ,[BusinessDay] ,[WeekDay] ,[Message]) VALUES (@db_name, @back_dir, @file, @type, @begintime, getdate(), @businessday, @weekday, null) END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; insert into [dbo].[BackupLogMessage]([DBName], [BackupTime], [Message]) SELECT @db_name, @begintime, convert(nvarchar(max), isnull(ERROR_NUMBER(), '')) + ','+ convert(nvarchar(max), isnull(ERROR_SEVERITY(), '')) + ',' + convert(nvarchar(max), isnull(ERROR_STATE(), '')) + ',' + convert(nvarchar(max), isnull(ERROR_LINE(), '')) + ',' + convert(nvarchar(max), isnull(ERROR_PROCEDURE(), '')) + ',' + convert(nvarchar(max), isnull(ERROR_MESSAGE(), '')) AS ErrorMessage; END CATCH; end |
8. Crm元数据查询Metadata
/// <summary> /// 检索对应实体元数据 /// </summary> /// <param name="entityName"></param> /// <param name="attributeName"></param> /// <returns></returns> private static EntityMetadata RetrieveEntityRequest(string entityName, EntityFilters filter) { RetrieveEntityRequest _RetrieveEntityRequest = new RetrieveEntityRequest() { LogicalName = entityName, EntityFilters = filter, //EntityFilters = EntityFilters.All, //EntityFilters = EntityFilters.Attributes, //EntityFilters = EntityFilters.Default, //EntityFilters = EntityFilters.Entity, //EntityFilters = EntityFilters.Privileges, //EntityFilters = EntityFilters.Relationships, }; RetrieveEntityResponse _RetrieveEntityResponse = (RetrieveEntityResponse) orgService.Execute(_RetrieveEntityRequest); EntityMetadata _EntityMetadata = _RetrieveEntityResponse.EntityMetadata; return _EntityMetadata; } /// <summary> /// 检索对应实体的字段元数据 /// </summary> /// <param name="entityName"></param> /// <param name="attributeName"></param> /// <returns></returns> private static AttributeMetadata RetrieveAttributeRequest(string entityName, string attributeName) { RetrieveAttributeRequest _RetrieveAttributeRequest = new RetrieveAttributeRequest() { EntityLogicalName = entityName, LogicalName = attributeName, }; RetrieveAttributeResponse _RetrieveAttributeResponse = (RetrieveAttributeResponse) orgService.Execute(_RetrieveAttributeRequest); AttributeMetadata _AttributeMetadata = _RetrieveAttributeResponse.AttributeMetadata; return _AttributeMetadata; } /// <summary> /// 检索所有实体元数据 /// </summary> /// <returns></returns> private static EntityMetadata[] RetrieveAllEntitiesRequest() { RetrieveAllEntitiesRequest _RetrieveAllEntitiesRequest = new RetrieveAllEntitiesRequest() { //EntityFilters = EntityFilters.All, //EntityFilters = EntityFilters.Attributes, //EntityFilters = EntityFilters.Default, EntityFilters = EntityFilters.Entity, //EntityFilters = EntityFilters.Privileges, //EntityFilters = EntityFilters.Relationships, }; RetrieveAllEntitiesResponse _RetrieveAllEntitiesResponse = (RetrieveAllEntitiesResponse)orgService.Execute(_RetrieveAllEntitiesRequest); EntityMetadata[] _EntityMetadata = _RetrieveAllEntitiesResponse.EntityMetadata; return _EntityMetadata; } /// <summary> /// 检索所有下拉类型字段元数据 /// </summary> /// <returns></returns> private static OptionSetMetadataBase[] RetrieveAllOptionSetsRequest() { RetrieveAllOptionSetsRequest _RetrieveAllOptionSetsRequest = new RetrieveAllOptionSetsRequest() {
}; RetrieveAllOptionSetsResponse retrieveAllOptionSetsResponse = (RetrieveAllOptionSetsResponse)orgService.Execute(_RetrieveAllOptionSetsRequest); OptionSetMetadataBase[] _OptionSetMetadataBase = retrieveAllOptionSetsResponse.OptionSetMetadata; return _OptionSetMetadataBase; } |
9.RetrieveMultiple分页查询数据
//查询客户 QueryExpression queryExpression = new QueryExpression("account"); if (!string.IsNullOrEmpty(name)) { ConditionExpression con = new ConditionExpression(); con.AttributeName = "name"; con.Operator = ConditionOperator.Like; con.Values.Add("%" + name + "%"); queryExpression.Criteria.AddCondition(con); } ConditionExpression stateCondition = new ConditionExpression(); stateCondition.AttributeName = "statecode"; stateCondition.Operator = ConditionOperator.Equal; stateCondition.Values.Add(0); PagingInfo pagingInfo = new PagingInfo(); pagingInfo.Count = 50; pagingInfo.PageNumber = page; queryExpression.ColumnSet = new ColumnSet("accountid", "name", "ownerid", "boc_accountno", "boc_branno"); queryExpression.AddOrder("boc_accountno", OrderType.Ascending); queryExpression.Criteria.AddCondition(stateCondition); queryExpression.PageInfo = pagingInfo; queryExpression.NoLock = true; queryExpression.LinkEntities.Add(new LinkEntity() { LinkFromEntityName = "account", LinkToEntityName = "systemuser", LinkFromAttributeName = "ownerid", LinkToAttributeName = "systemuserid", Columns = new ColumnSet("businessunitid"), EntityAlias = "accountowner" }); EntityCollection entityCollection = orgService.RetrieveMultiple(queryExpression); |