.Net Dust

.Net Dust

http://dotnetdust.blogspot.com

NULL

Allow Native Mapping When Referencing a Parent Entity

Published

Normal Out of Box (OOB) CRM Relationship mapping can be extremely beneficial, but it has a very big “gotcha”.  They only work when creating a child entity from the parent form.  So if the user is on the Parent Entity Form, and adding a new entity via a Grid, then the mapping will automatically be populated for the user.  But what happens if you have an entity that is serving as a M:M entity (think Lead Products).   Generally, a user would create a Lead Product from the Lead Form.  This means if any mappings are setup from the Product to the Lead Product, they will not be applied.

There is no way for this to get applied natively, since the mapping takes place before the Lead Product is loaded, but the user doesn’t select a Product until after the Lead Product is loaded.  There is however, a simple partial work around.  Create a plugin that performs the mapping using what is defined in the OOB Field Mapping for the Relationship.  For extensibility, define the parent field(s) in the plugin step.  Below is a working example of such a plugin (utilizing the DLaB.Xrm.2016 NuGet Package).

public override void RegisterEvents()
{
    RegisteredEvents.AddRange(new RegisteredEventBuilder(PipelineStage.PreOperation, MessageType.Create).Build());
}
 
protected override void ExecuteInternal(ExtendedPluginContext context)
{
    if (UnsecureConfig == null)
    {
        context.Trace("No Fields listed in the Unsecure Configuration.  Nothing from which to initialize the entity!");
        return;
    }
    var target = context.GetTarget<Entity>();
    foreach (var field in UnsecureConfig.Split(new [] {",","|",Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries))
    {
        InitializeFromField(context, target, field);
    }
}
 
/// <summary>
/// Loads the configured mappings for the entity from the given field. 
/// Only attributes that do not exist in the target are set, and only if the field contains an EntityReference in the target
/// </summary>
/// <param name="context">The context.</param>
/// <param name="target">The target.</param>
/// <param name="field">The field.</param>
private void InitializeFromField(ExtendedPluginContext context, Entity target, string field)
{
    context.TraceFormat("Initializing from field {0}", field);
    var parent = target.GetAttributeValue<EntityReference>(field);
    if (parent == null)
    {
        context.TraceFormat("No Parent found for field {0}", field);
        return;
    }
    var mappedEntity = context.SystemOrganizationService.InitializeFrom(parent, target.LogicalName, TargetFieldType.ValidForCreate);
    foreach (var att in mappedEntity.Attributes.Where(a => !target.ContainsAllNonNull(a.Key)))
    {
        context.TraceFormat("Adding attribute {0}:{1}", att.Key, att.Value);
        target.Attributes.Add(att);
    }
}

The Details

  • The Plugin must be registered for each entity to be initialized
  • The Unsecure Configuration Settings must contain a comma (or pipe or newline) delimited list of parent lookup attributes to initialize the entity from. i.e. “ProductId”
  • The parent field lookup field must be populated on the initial save.
  • Only un-populated fields will be mapped.  If a user has defined a value already, it will not be overridden.
  • An end user will not see the mapped values on the form until after the initial save refresh occurs.
That’s it.  A few lines of code, and now your Entity Relations Field Mappings can be used in many more places!

Continue to website...

More from .Net Dust

Related Posts