CRM 2011 插件检查一个帐户是否有 parent

CRM 2011 plugin to check whether an Account has a parent

我正在用 C# 为 Dynamics CRM 2011 (On Prem) 编写插件。
该插件是为了防止帐户记录中出现祖父关系(帐户可以有 children 或 parent,但不能同时有两者)。

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

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

为 parent 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 始终为假,因为 account.ParentAccountId 为空。我不知道为什么,因为肯定有一个 parent 帐户与此记录相关联,属性名称肯定是 parentaccountid.

查找 child 帐户的调用使用 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 并且它 returns false 我认为与问题有关:

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

我做错了什么?

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

这样做

 // 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"],因此当将实体转换为帐户。上面是如何进行查询以获取插件中的完整记录,并且它将始终被填充,除非插件是在创建前注册的(在这种情况下,您当前的代码可以正常工作,但是由于您正在一个空值,我假设你没有在前期创建时注册)。