【问题标题】:Getting an early-bound relationship建立早期绑定关系
【发布时间】:2017-07-11 14:10:53
【问题描述】:

当我将注释链接到特定实体时,而不是像这样创建关系:

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

是否可以用强类型的方式引用关系:

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

这类似于能够在开发时获取逻辑名称:

SalesOrder.EntityLogicalName

我们能否以同样的方式引用具体的 1:N 关系:

SalesOrder.Relationships.SalesOrder_Annotation

【问题讨论】:

  • SalesOrder.Relationships.SalesOrder_Annotation返回的类型是什么?如果不是Relationship,那么不,你不能调用它。我不得不问,因为使用标准 CrmSvcUtil.exe 代码生成工具无法使用 SalesOrder.Relationships.SalesOrder_Annotation - 所以它很可能是自定义的。
  • 是否有任何使用 crmsvcutil 可用的关系可以使用 entity.relationship 名称或类似名称调用?
  • 不。您必须创建一个扩展来生成带有关系名称的constreadonly 字符串。或者写一个方法从CrmSvcUtil.exe输出的code属性中读取关系名。
  • @Nicknow 有例子吗? :)
  • @l--''''''---------'''''''''''' 你用过任何答案吗?

标签: c# .net visual-studio c#-4.0 dynamics-crm-2011


【解决方案1】:

如果您使用 SDK 中提供的标准 CrmSvcUtil.exe 应用程序 (\SDK\Bin\CrmSvcUtil.exe) 生成代码,则您要查找的值存储在代码属性 RelationshipSchemaNameAttribute 中。我已经使用 SDK (\SDK\SampleCode\CS\HelperCode\MyOrganizationCrmSdkTypes.cs) 中提供的早期绑定实体类文件在控制台应用程序中验证了此代码。

按如下方式调用该方法(根据您的示例):

var relationship = GetRelationship&lt;SalesOrder&gt;(nameof(SalesOrder.SalesOrder_Annotation))

或者如果你想返回实际的字符串值:

var relationshipName = GetRelationshipSchemaName&lt;SalesOrder&gt;(nameof(SalesOrder.SalesOrder_Annotation))

将此代码添加到应用程序中的帮助程序类中:

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);
}

这是您更新后的代码的样子:

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)) ///////////????
                                   };

【讨论】:

    【解决方案2】:

    再想一想,我的 t4 模板答案似乎有点矫枉过正
    您可以使用表达式树和扩展方法来轻松获得所需的内容

    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; }
        }
    }
    

    【讨论】:

      【解决方案3】:

      根据您的说法,您生成的类有一个带有关系名称的属性。
      您所需要的只是一个 t4 模板,它可以为您的关系生成一个具有强类型属性的类

      假设您的项目中有以下代码

      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 { }
      
      }
      

      这个模板

      <#@ 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 #>";
              }
            <# }
      
        #>}
      }
      

      将生成以下 .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";
               }
         }
      }
      

      那么你就可以像这样使用它了

      Relationship = new Relationship(Relationships.Class1.RelationShipA )
      

      【讨论】:

      • @Downvoter 不确定这个答案是否值得被否决...它可能比其他答案更复杂,但另一方面它没有性能损失...如果 OP 想要使用它的代码循环它可能是最好的答案
      【解决方案4】:

      我不确定我的问题是否正确。 C# 6.0 特性 nameof(...) 不会做这件事吗?

      即。

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

      【讨论】:

      • 问题(据我了解)是“RelationshipSalesOrder.Relationships.SalesOrder_Annotation”不存在。如果存在,是的,你可以这样做
      • @GeorgeVovos 是正确的。没有RelationshipSalesOrder.Relationships.SalesOrder_Annotation,即使它存在,也不一定匹配Relationship 构造函数需要的字符串值。
      【解决方案5】:

      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";
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-15
        • 1970-01-01
        • 1970-01-01
        • 2010-10-03
        • 1970-01-01
        • 1970-01-01
        • 2016-01-01
        • 2012-01-15
        相关资源
        最近更新 更多