Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are all reference properties null in my CRM plugin?

I'm writing a PostUpdate Plugin on the contact entity using early binding.
Unfortunately, all properties which should represent 1:x relations are null.
The code is pretty simple:
* CRMcontext is the generated file via CrmSvcUtil.exe,
* service is the IOrganizationService from LocalPluginContext:

using ( var serviceContext = new CRMcontext(service) )
{
  // This works fine
  var contact = serviceContext.CreateQuery<Contact>().First(c => c.Id == context.PrimaryEntityId);

  // why is currency null after this line?! (and yes, it's set in the entity)
  var currency = contact.transactioncurrency_contact;
}

I followed this example (the last code snippet): http://msdn.microsoft.com/en-us/library/gg695791.aspx

Thanks for any help!

Edit:

/// <summary>
/// N:1 transactioncurrency_contact
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("transactioncurrencyid")]
[Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("transactioncurrency_contact")]
public TransactionCurrency transactioncurrency_contact
{
    get
    {
        return this.GetRelatedEntity<TransactionCurrency>("transactioncurrency_contact", null);
    }
    set
    {
        this.OnPropertyChanging("transactioncurrency_contact");
        this.SetRelatedEntity<TransactionCurrency>("transactioncurrency_contact", null, value);
        this.OnPropertyChanged("transactioncurrency_contact");
    }
}
like image 603
Sascha Avatar asked Oct 02 '22 20:10

Sascha


2 Answers

CRM doesn't load the related entity properties automatically. You'll need to call LoadProperty on each property that is lazily loaded.

And LameCoder is incorrect, LINQ to CRM doesn't generate Fetch Xml, but QueryExpressions, which is why it is limited to whatever capability QueryExpressions possess.

Edit 1 - Why doesn't this work implicitly as the last example in the MSDN article states?

The GetRelatedEntity method is defined as so:

protected virtual IEnumerable<TEntity> GetRelatedEntities<TEntity>(string relationshipSchemaName, EntityRole? primaryEntityRole) where TEntity : Entity
{
  if (string.IsNullOrWhiteSpace(relationshipSchemaName))
    throw new ArgumentNullException("relationshipSchemaName");
  Relationship key = new Relationship(relationshipSchemaName)
  {
    PrimaryEntityRole = primaryEntityRole
  };
  if (!this.RelatedEntities.Contains(key))
    return (IEnumerable<TEntity>) null;
  else
    return Enumerable.Cast<TEntity>((IEnumerable) this.RelatedEntities[key].Entities);
}

If your early bound entity inherits from Entity, then only thing it is doing is accessing it's own internal RelatedEntities collection. It is doing nothing to access the server to load the related property.

If you use the CodeGeneration.CodeCustomization to generate the early bound entities it should work as you have listed, because it'll inherit from CrmEntity, which will load the relationships for you since it overrides the GetRelatedEntity method uses the context to fetch it for you.

like image 127
Daryl Avatar answered Oct 12 '22 23:10

Daryl


My understanding is that the LINQ query is just going to create FetchXML, which will not expand relationships unless you specifically request it.

You should do a join in your LINQ query to get the relationships you need, but be aware that according to the CRM 2013 SDK LINQ queries only support inner joins. So you won't be able to get back records that are missing the relationship.

If you use the SVC Util to generate your earlybound types with the SDK extensions assemblies (which may be difficult to use within a plugin) the Context that the extension has is capable of auto-expanding when you access the property. See the Microsoft.Xrm.Client.CrmOrganizationServiceContext class for details, you'd need to attach the entity to the context if it isn't already by calling Attach. Keep in mind that this is just going to do a query for the relationship lazily, so it'll be multiple queries behind the scene.

If you want it all in one query, and need a LEFT join, try using FetchXML directly.

Edit: Also notice that in the MSDN link you specified, the example is trying to show how the related entity is null unless you call LoadProperty. So you could just simply call LoadProperty to load what you need.

like image 30
LameCoder Avatar answered Oct 13 '22 00:10

LameCoder