【问题标题】:CRM 2011 plugin to check whether an Account has a parentCRM 2011 插件,用于检查帐户是否有父级
【发布时间】:2016-05-11 15:42:41
【问题描述】:

我正在为 Dynamics CRM 2011 (On Prem) 编写 C# 插件。
该插件是为了防止帐户记录中的祖父关系(帐户可以有孩子或父母,但不能同时拥有)。

我正在努力检查帐户是否有关联的父级,父级 ID 的属性始终为空,我不明白为什么。

我已经使用crmsvcutil.exe 正确生成了早期绑定类并将文件添加到我的项目中。

为父 ID 生成的代码如下所示:

/// <summary>
/// Unique identifier of the parent account.
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("parentaccountid")]
public Microsoft.Xrm.Sdk.EntityReference ParentAccountId
{
    get
    {
        return this.GetAttributeValue<Microsoft.Xrm.Sdk.EntityReference>("parentaccountid");
    }
    set
    {
        this.OnPropertyChanging("ParentAccountId");
        this.SetAttributeValue("parentaccountid", value);
        this.OnPropertyChanged("ParentAccountId");
    }
}

我的插件的基本版本如下所示:

namespace NoGrandparentAccounts
{
    using CRM2011GeneratedBusinessModel; // Namespace for crmsvcutil generated early bound classes
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using System;
    using System.ServiceModel;

    public class Main : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // OBTAIN EXECUTION CONTEXT
            var context(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // TRACING SERVICE FOR LOGGING
            var tracingService =
            (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            // WILL REPRESENT THE CURRENT ENTITY
            Entity entity = null;

            // INPUTPARAMETERS COLLECTION CONTAINS ALL DATA PASSED IN THE MESSAGE REQUEST
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                // SET ENTITY TO THE CURRENT ENTITY
                entity = (Entity)context.InputParameters["Target"];

                // CHECK WE'RE IN ACCOUNTS ENTITY
                if (context.PrimaryEntityName != "account")
                    return;

                // CHECK WE'RE CREATING OR UPDATING THE ENTITY
                if (context.MessageName != "Create" && context.MessageName != "Update")
                    return;
            }
            else
            {
                return;
            }

            try
            {
                // GET ORGANIZATION SERVICE
                var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                var service = serviceFactory.CreateOrganizationService(context.UserId);

                // GET CURRENT ACCOUNT
                var account = entity.ToEntity<Account>();

                // HAS A PARENT ACCOUNT?
                var hasParent = (account.ParentAccountId != null && account.ParentAccountId.Id != Guid.Empty);
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                tracingService.Trace($@"Exception: {ex.Message} - {ex.StackTrace}");
                throw new InvalidPluginExecutionException(@"An error occurred in the plugin.", ex);
            }
            catch (Exception ex)
            {
                tracingService.Trace($@"Exception: {ex.Message} - {ex.StackTrace}");
                throw new InvalidPluginExecutionException(@"An error occurred in the plugin.", ex);
            }
        }
    }
}

不幸的是,hasParent 始终为 false,因为 account.ParentAccountId 为空。我不知道为什么,因为这条记录肯定有一个父帐户关联,并且属性名称肯定是parentaccountid

使用parentaccountid 调用查找子帐户可以正常工作:

// FETCH CHILDREN
var cExpr = new ConditionExpression("parentaccountid", ConditionOperator.Equal, account.Id);
var qExpr = new QueryExpression(Account.EntityLogicalName);
qExpr.ColumnSet = new ColumnSet(new string[] { "accountid" });
qExpr.Criteria.AddCondition(cExpr);
var results = service.RetrieveMultiple(qExpr);

// HAS CHILDREN
var hasChildren = results.Entities.Count > 0;

实体计数正确显示为 3,因此 hasChildren 为真。

我检查了该实体的属性是否包含 parentaccountid 并且它返回 false,我认为这与问题有关:

if (entity.Attributes.Contains("parentaccountid"))
{
    // Never gets here as this is false!?
}

我做错了什么?

【问题讨论】:

    标签: c# plugins dynamics-crm-2011


    【解决方案1】:

    Target 实体本身只包含基本的实体身份数据。如果你想访问实体的属性,你应该使用你想访问 context.PreEntityImages 的属性配置一个合适的 PreImage 或 PostImage,然后你可以通过context.PreEntityImagescontext.PostEntityImages 检索它。或者(并且不太理想)您可以使用您想要的属性从插件中检索实体的最新版本。

    【讨论】:

    • 我想我做了第二个:var account = (Account)service.Retrieve("account", entity.ToEntity&lt;Account&gt;().Id, new ColumnSet(new string[] { "accountid", "parentaccountid" }));。我主要理解第一个,但不知道从哪里开始。任何提示或指南?我不确定要搜索的关键字是什么。
    • 目标实体不仅仅包含基本的实体身份数据。在 Create 中,它将包含随 CreateRequest 一起发送的所有字段。在更新中,它将仅包含已更新的字段。如果您不更新 ParentAccountId 字段,那么您的 Target 实体将没有该属性。答案的另一部分是绝对正确的。使用 PluginRegistrationTool 包括一个 PreImage 指定 ParentAccountId 字段。然后在您的代码中,首先检查 Target 是否包含 ParentAccountId(意味着它刚刚被更改)。否则,从 PreEntity 获取。
    • 谢谢大家,我相信将我指向图片已经解决了我的问题。
    【解决方案2】:

    这样做

     // GET CURRENT ACCOUNT
     var account = (Account)service.Retrieve("account", entity.Id, new ColumnSet(new string[] { "accountid", "parentaccountid" })); 
    

    不是这个

    // GET CURRENT ACCOUNT
    var account = entity.ToEntity<Account>();
    

    正如 Josh Painter 在他的评论中指出的那样,您注册的事件可能没有将此值传递给 PluginExecutionContext.InputParameters["Target"],因此在将实体转换为帐户时属性变为 null .以上是如何进行查询以获取插件中的完整记录,并且始终会填充该记录,除非该插件已在 pre-stage create 注册(在这种情况下,您当前的代码可以正常工作,但是由于您正在一个空值,我假设您没有在 pre-stage create 上注册)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-28
      相关资源
      最近更新 更多