Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting an early-bound relationship

When I am linking annotations to a specific entity, rather than creating a relationship like so:

var associateRequest = new AssociateRequest
{
    Target = new EntityReference(SalesOrder.EntityLogicalName, salesOrderGuid),
    RelatedEntities = new EntityReferenceCollection
    {
        new EntityReference(Annotation.EntityLogicalName, noteGuid),
    },
    Relationship = new Relationship("SalesOrder_Annotation")
};

Is it possible to reference the relationship in a strongly typed way:

var associateRequest = new AssociateRequest
{
    Target = new EntityReference(SalesOrder.EntityLogicalName, salesOrderGuid),
    RelatedEntities = new EntityReferenceCollection
    {
        new EntityReference(Annotation.EntityLogicalName, noteGuid)
    },
    Relationship = SalesOrder.Relationships.SalesOrder_Annotation // <----- ???
};

This would be similar to being able to get the logicalname at develop time:

SalesOrder.EntityLogicalName

Can we reference the specific 1:N relationship the same way:

SalesOrder.Relationships.SalesOrder_Annotation
like image 733
Alex Gordon Avatar asked Feb 21 '17 19:02

Alex Gordon


People also ask

When we should go with early binding and when with late binding?

The key difference between early and late binding involves type conversion. While early binding provides compile-time checking of all types so that no implicit casts occur, late binding checks types only when the object is created or an action is performed on the type.

What is an early-bound class?

Early-bound programming requires that you first generate a set of classes based on the table and column definitions (entity and attribute metadata) for a specific environment using the code generation tool (CrmSvcUtil.exe). More information: Generate classes for early-bound programming using the Organization service.

How do I generate early-bound classes in Dynamics 365?

Run the code generation tool Run the CrmSvcUtil.exe tool from the Tools\CoreTools folder created when you downloaded the tools using the script described in Download tools from NuGet. If you run the tool from another folder location, make sure that a copy of the Microsoft. Xrm. Sdk.

How do you generate early-bound classes in dynamics 365 using Xrmtoolbox?

On the left pane, users can choose to generate the early-bound . NET files for the Entities, the Option Set, and/or and Actions. A click on the button will launch a command prompt and the command line used to create the classes will be displayed on the left pane.


2 Answers

The value you are looking for is stored in a code attribute, RelationshipSchemaNameAttribute, if you generate your code using the standard CrmSvcUtil.exe application provided in the SDK (\SDK\Bin\CrmSvcUtil.exe). I've validated this code in a console application using the early bound entity class file provided in the SDK (\SDK\SampleCode\CS\HelperCode\MyOrganizationCrmSdkTypes.cs).

Call the method as follows (per your example):

var relationship = GetRelationship<SalesOrder>(nameof(SalesOrder.SalesOrder_Annotation))

Or if you want to return the actual string value:

var relationshipName = GetRelationshipSchemaName<SalesOrder>(nameof(SalesOrder.SalesOrder_Annotation))

Add this code to a helper class in your application:

public static string GetRelationshipSchemaName<T>(string relationshipPropertyName) where T:Entity
{
    return typeof (T).GetProperties()
        .FirstOrDefault(x => x.Name == relationshipPropertyName)
        .GetCustomAttributes()
        .OfType<RelationshipSchemaNameAttribute>()
        .FirstOrDefault()
        ?.SchemaName;            
}

public static Relationship GetRelationship<T>(string relationshipPropertyName) where T : Entity
{
    return new Relationship(typeof(T).GetProperties()
        .FirstOrDefault(x => x.Name == relationshipPropertyName)
        .GetCustomAttributes()
        .OfType<RelationshipSchemaNameAttribute>()
        .FirstOrDefault()
        ?.SchemaName);
}

This is what your updated code would look like:

var associateRequest = new AssociateRequest
                                   {
                                       Target =
                                           new EntityReference(
                                               SalesOrder.EntityLogicalName,
                                               salesOrderGuid),
                                       RelatedEntities =
                                           new EntityReferenceCollection
                                               {
                                                   new EntityReference(
                                                       Annotation
                                                           .EntityLogicalName,
                                                       noteGuid)
                                               },
                                       Relationship = GetRelationship<SalesOrder>(nameof(SalesOrder.SalesOrder_Annotation)) ///////////????
                                   };
like image 141
Nicknow Avatar answered Oct 12 '22 22:10

Nicknow


On second thought ,my t4 template answer seems an overkill
You can use expression trees and an extension method to easily get what you need

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApplication9
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Relationship r = new Class1().GetRelationShip(s => s.RelationShipProperty);
            Console.WriteLine(r.Name);
            System.Console.ReadLine();
        }
    }

    public static class MyExtention
    {
        public static Relationship GetRelationShip<T, TProperty>(this T t, Expression<Func<T, TProperty>> expression)
        {
            return new Relationship(((expression.Body as MemberExpression).Member as PropertyInfo)
                    .GetCustomAttributes(typeof(RelationshipAttribute))
                    .Select(a=>(RelationshipAttribute)a)
                    .First().Name
                    );
        }
    }

    public class RelationshipAttribute : System.Attribute
    {
        public string Name { get; set; }

        public RelationshipAttribute(string name)
        {
            Name = name;
        }
    }

    public class Relationship
    {
        public string Name { get; set; }

        public Relationship(string name)
        {
            Name = name;
        }
    }

    public class Class1
    {
        [Relationship("RelationShipA")]
        public List<int> RelationShipProperty { get; set; }
    }
}
like image 20
George Vovos Avatar answered Oct 13 '22 00:10

George Vovos