2017-02-21 37 views
14

当我链接注释到特定的实体,而不是创造像这样的关系:获得一个早期绑定关系

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

这将是类似能够得到logicalname在开发时间:

SalesOrder.EntityLogicalName 

我们可以参考具体的1:N的关系一样:

SalesOrder.Relationships.SalesOrder_Annotation 
+0

'SalesOrder.Relationships.SalesOrder_Annotation'返回的类型是什么?如果它不是“关系”,那么不是,你不能称它。我不得不问,因为'SalesOrder.Relationships.SalesOrder_Annotation'不可用使用标准的CrmSvcUtil.exe代码gen工具 - 所以它非常自定义。 – Nicknow

+0

是否使用可使用entity.relationship名称或类似方法调用的crmsvcutil可用的任何关系? –

+0

不是。你将不得不创建一个扩展来生成具有关系名称的'const'或'readonly'字符串。或者写一个方法从'CrmSvcUtil.exe'输出的代码属性中读取关系名称。 – Nicknow

回答

4

从你说的话,你生成的类必须与你的关系的名称的属性。
所有你需要的是,对你的人际关系产生具有强类型属性的类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) 
+1

@Downvoter不知道这个答案值得downvote ...它可能比其他人更复杂,但另一方面它没有性能损失......如果OP想要使用代码它循环它可能是最好的答案 –

6

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

呼叫的方法如下(按你的例子​​):

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

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

var relationshipName = GetRelationshipSchemaName<SalesOrder>(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)) ///////////???? 
            }; 
5

关于第二个想法,我的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; } 
    } 
} 
4

我不确定我是否正确回答问题。 不会C#6.0功能nameof(...)做的事情?

即。

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

问题(据我所知)是“RelationshipSalesOrder.Relationships.SalesOrder_Annotation”不存在。如果存在,是的,你可以这样做 –

+0

@GeorgeVovos是正确的。没有'RelationshipSalesOrder.Relationships.SalesOrder_Annotation',即使它存在,也不一定匹配'Relationship'构造函数需要的字符串值。 – Nicknow