简体   繁体   English

获得早期绑定关系

[英]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:我们能否以同样的方式引用具体的 1:N 关系:

SalesOrder.Relationships.SalesOrder_Annotation

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 ).如果您使用 SDK ( \SDK\Bin\CrmSvcUtil.exe ) 中提供的标准CrmSvcUtil.exe应用程序生成代码,则您要查找的值存储在代码属性RelationshipSchemaNameAttribute中。 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 ).我已经使用 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转念一想,我的 t4 模板答案似乎有点矫枉过正
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; }
    }
}

I'm not sure whether I got the question right.我不确定我是否答对了问题。 Wouldn't C# 6.0 feature nameof(...) do the thing? C# 6.0 功能nameof(...)不会做这件事吗?

ie. IE。

new Relationship(nameof(RelationshipSalesOrder.Relationships.SalesOrder_Annotation));

From what you said, your generated classes have an attribute with the name of your relationship.根据您所说,您生成的类有一个属性,其中包含您的关系名称。
All you need is a t4 template that generates a class with strongly typed properties for your Relationships您只需要一个 t4 模板,它可以为您的关系生成一个具有强类型属性的类

Let's say you have the following code in your project假设您的项目中有以下代码

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

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

    [Relationship("RelationShipA")]
    public class Class1 { }

    [Relationship("RelationShipB")]
    public class Class2 { }

    [Relationship("RelationShipC")]
    public class Class3 { }

}

This template这个模板

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(TargetPath)" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ output extension=".cs" #>

namespace YourNameSpace
{
   public static class Relationships
   {
      <# 
         var types = typeof(ConsoleApplication9.RelationshipAttribute).Assembly
                     .GetTypes()
                     .Select(t => new { t.Name, Value = t.GetCustomAttribute(typeof(ConsoleApplication9.RelationshipAttribute)) })
                     .Where(t => t.Value != null)
                     .Select(t=> new { t.Name,Value= ((ConsoleApplication9.RelationshipAttribute)t.Value).Name })
                     .ToList();

                 foreach (var attr in types)
  { #>
 public static class  <#=  attr.Name #>
        {
            public const string <#=  attr.Value #> = "<#=  attr.Value #>";
        }
      <# }

  #>}
}

will produce the following.cs file会产生如下.cs文件

namespace YourNameSpace
{
   public static class Relationships
   {
         public static class  Class1
         {
           public const string RelationShipA = "RelationShipA";
         }
         public static class  Class2
         {
           public const string RelationShipB = "RelationShipB";
         }
         public static class  Class3
         {
           public const string RelationShipC = "RelationShipC";
         }
   }
}

Then you can use it like然后你可以像这样使用它

Relationship = new Relationship(Relationships.Class1.RelationShipA )

The Early Bound Generator in the XrmToolBox will generate these relationship names for you. XrmToolBox 中的 Early Bound Generator 将为您生成这些关系名称。

public static class Fields
{
    public const string AccountId = "accountid";
    public const string AccountRoleCode = "accountrolecode";
    public const string Address1_AddressId = "address1_addressid";
    // *** SNIP *** 
    public const string YomiLastName = "yomilastname";
    public const string YomiMiddleName = "yomimiddlename";
    public const string business_unit_contacts = "business_unit_contacts";
    public const string contact_customer_accounts = "contact_customer_accounts";
    public const string Referencingcontact_customer_contacts = "contact_customer_contacts";
    public const string Referencingcontact_master_contact = "contact_master_contact";
    public const string contact_owning_user = "contact_owning_user";
    public const string lk_contact_createdonbehalfby = "lk_contact_createdonbehalfby";
    public const string lk_contact_modifiedonbehalfby = "lk_contact_modifiedonbehalfby";
    public const string lk_contactbase_createdby = "lk_contactbase_createdby";
    public const string lk_contactbase_modifiedby = "lk_contactbase_modifiedby";
    public const string system_user_contacts = "system_user_contacts";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM