Por que todas as propriedades de referência são nulas em meu plug-in do CRM?

Estou escrevendo um plug-in do PostUpdate na entidade de contato usando a vinculação antecipada.
Infelizmente, todas as propriedades que deveriam representar relações 1: x são nulas.
O código é bem simples:
* CRMcontext é o arquivo gerado via CrmSvcUtil.exe,
* service é o IOrganizationService do LocalPluginContext:

using ( var serviceContext = new CRMcontext(service) ) { // This works fine var contact = serviceContext.CreateQuery().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; } 

Eu segui este exemplo (o último trecho de código): http://msdn.microsoft.com/pt-br/library/gg695791.aspx

Obrigado por qualquer ajuda!

Editar:

 ///  /// N:1 transactioncurrency_contact ///  [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("transactioncurrencyid")] [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("transactioncurrency_contact")] public TransactionCurrency transactioncurrency_contact { get { return this.GetRelatedEntity("transactioncurrency_contact", null); } set { this.OnPropertyChanging("transactioncurrency_contact"); this.SetRelatedEntity("transactioncurrency_contact", null, value); this.OnPropertyChanged("transactioncurrency_contact"); } } 

O CRM não carrega as propriedades da entidade relacionadas automaticamente. Você precisará chamar LoadProperty em cada propriedade que é carregada com preguiça.

E o LameCoder está incorreto, o LINQ para o CRM não gera o Fetch Xml, mas o QueryExpressions , e é por isso que ele é limitado a qualquer recurso que o QueryExpressions possua.

Editar 1 – Por que isso não funciona implicitamente como o último exemplo no artigo do MSDN afirma?

O método GetRelatedEntity é definido da seguinte forma:

 protected virtual IEnumerable GetRelatedEntities(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) null; else return Enumerable.Cast((IEnumerable) this.RelatedEntities[key].Entities); } 

Se sua entidade de binding inicial herdar de Entity , a única coisa que está fazendo é acessar sua própria coleção interna de RelatedEntities. Não está fazendo nada para acessar o servidor para carregar a propriedade relacionada.

Se você usar CodeGeneration.CodeCustomization para gerar as primeiras entidades vinculadas, ele deve funcionar como você listou, porque ele herdará de CrmEntity , que carregará os relacionamentos para você, já que ele substitui o método GetRelatedEntity e usa o contexto para buscá-lo para você .

Meu entendimento é que a consulta LINQ criará o FetchXML, que não expandirá os relacionamentos, a menos que você o solicite especificamente.

Você deve fazer uma junit em sua consulta LINQ para obter os relacionamentos necessários, mas lembre-se de que, de acordo com as consultas LINQ do SDK do CRM 2013, somente as junções internas são suportadas. Então você não será capaz de recuperar os registros que estão faltando no relacionamento.

Se você usar o SVC Util para gerar seus tipos iniciais com os assemblies de extensões do SDK (que podem ser difíceis de usar em um plug-in), o Contexto que a extensão possui é capaz de expansão automática quando você acessa a propriedade. Veja a class Microsoft.Xrm.Client.CrmOrganizationServiceContext para detalhes, você precisaria append a entidade ao contexto se já não estiver chamando Attach. Tenha em mente que isso só vai fazer uma consulta para o relacionamento preguiçosamente, por isso vai ser várias consultas por trás da cena.

Se você quiser tudo em uma consulta e precisar de uma associação LEFT, tente usar o FetchXML diretamente.

Edit: Observe também que no link do MSDN que você especificou, o exemplo está tentando mostrar como a entidade relacionada é nula, a menos que você chame LoadProperty. Então você poderia simplesmente chamar LoadProperty para carregar o que você precisa.

Para a atualização de 2016 do CRM, algumas coisas mudaram. Agora você deve usar o método LoadProperty como Daryl sugeriu. Isso vai funcionar.

Eu usei o CodeGeneration.CodeCustomization para gerar as entidades de limite iniciais, mas parece que o SDK do CRM 2016 não tem o Microsoft.Xrm.Client.CodeGeneration.dll necessário mais infelizmente. Então, desta forma não funciona mais a partir da atualização de 2016.