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
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.
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.
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.
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.
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)) ///////////????
};
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; }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With