Enums 如何使CRMSvcUtil.exe生成未重复、无错误的早期绑定选项集?

Enums 如何使CRMSvcUtil.exe生成未重复、无错误的早期绑定选项集?,enums,dynamics-crm,dynamics-crm-2011,Enums,Dynamics Crm,Dynamics Crm 2011,我使用Erik Pool的实现和Manny Grewal的函数作为模型来过滤CRMSvcUtil生成的文件中不需要的实体。Erik建议为generateOptions Set方法返回true以生成选项集的enum,但这样做会复制任何特定实体使用的任何全局选项集(如该帖子中所述) 为了解决这个问题,我检查选项集是否已经生成,如果已经生成,我将返回默认选项(大多数情况下可能是false),如下所示 //生成的选项集列表,在构造函数中实例化 私有列表生成选项集; 公共布尔生成选项集 (OptionSe

我使用Erik Pool的实现和Manny Grewal的函数作为模型来过滤
CRMSvcUtil
生成的文件中不需要的实体。Erik建议为
generateOptions Set
方法返回
true
以生成选项集的
enum
,但这样做会复制任何特定实体使用的任何全局选项集(如该帖子中所述)

为了解决这个问题,我检查选项集是否已经生成,如果已经生成,我将返回默认选项(大多数情况下可能是
false
),如下所示

//生成的选项集列表,在构造函数中实例化
私有列表生成选项集;
公共布尔生成选项集
(OptionSetMetadataBase optionSetMetadata,IServiceProvider服务)
{
如果(!GeneratedOptionSets.Contains(optionSetMetadata.Name))
{
GeneratedOptionSets.Add(optionSetMetadata.Name);
返回true;
}
return _defaultService.GenerateOptionSet(optionSetMetadata,services);
}
但是在将生成的文件合并到我的CRM项目中时,编译错误

总是由看起来像

this.SetAttributeValue
((address1_shippingmethodcode),新的Microsoft.Xrm.Sdk.OptionSetValue((int)(value));

作为一种解决方法,我使用一个单独的项目来过滤我需要的实体,用Erik建议的参数运行
CRMSvcUtil
,在生成文件后,用
value
(其中
value
是一个
OptionSetValue
)替换代码中麻烦的部分
(int)(value)
,然后重新保存文件,所有问题都会消失


我的问题是:我是否需要做一些不同的事情,用默认的
CRMSvcUtil
生成的文件来修复这个编译错误,而不做一些像修改生成的文件这样的粗俗的事情?

您可以使用
ICustomizeCodeDomService
接口来重写选项集。下面的片段:

namespace The.NameSpace
{
 using System;
 using System.CodeDom;
 using System.Diagnostics;
 using System.Linq;

 using Microsoft.Crm.Services.Utility;
 using Microsoft.Xrm.Sdk.Metadata;

/// <summary>
/// The customize code dom service.
/// </summary>
public sealed class CustomizeCodeDomService : ICustomizeCodeDomService
{
    #region Constants and Fields

    /// <summary>
    ///   The metadata.
    /// </summary>
    private IOrganizationMetadata metadata;

    #endregion

    #region Properties



    #endregion

    #region Public Methods

    /// <summary>
    /// The customize code dom.
    /// </summary>
    /// <param name="codeCompileUnit">
    /// The code compile unit.
    /// </param>
    /// <param name="services">
    /// The services.
    /// </param>
    public void CustomizeCodeDom(CodeCompileUnit codeCompileUnit, IServiceProvider services)
    {
        // Locate the namespace to use
        CodeNamespace codeNamespace = codeCompileUnit.Namespaces[0];

        var metadataProviderService = (IMetadataProviderService)services.GetService(typeof(IMetadataProviderService));
        var filterService = (ICodeWriterFilterService)services.GetService(typeof(ICodeWriterFilterService));

        this.metadata = metadataProviderService.LoadMetadata();

        foreach (EntityMetadata entityMetadata in this.metadata.Entities)
        {
            if (filterService.GenerateEntity(entityMetadata, services))
            {
                CodeTypeDeclaration entityClass =
                    codeNamespace.Types.Cast<CodeTypeDeclaration>().First(codeType => codeType.Name.ToUpper() == entityMetadata.SchemaName.ToUpper());

                UpdateEnumSetter(entityClass, entityMetadata);

            }
        }
    }

    #endregion

    #region Private Methods
    private static void UpdateEnumSetter(
  CodeTypeDeclaration entityClass, EntityMetadata entity)
    {
        foreach (var attributeMetadata in entity.Attributes.Where(attributeMetadata => String.IsNullOrWhiteSpace(attributeMetadata.AttributeOf)))
        {
            //Match the respective field Name. 
            AttributeMetadata metadata1 = attributeMetadata;
            foreach (
                CodeTypeMember codeMembers in
                    entityClass.Members.Cast<CodeTypeMember>().Where(
                        codeMembers => codeMembers.Name == metadata1.SchemaName))
            {
                var codeProperty = (CodeMemberProperty)codeMembers;

                if (codeProperty.HasSet)
                {
                    if (attributeMetadata.AttributeType != null && attributeMetadata.AttributeType.Value == AttributeTypeCode.Picklist)
                    {
                        ((CodeConditionStatement)codeProperty.SetStatements[1]).FalseStatements[0] =
                            new CodeSnippetStatement
                            {
                                Value =
                                    String.Format(
                                        "this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));",
                                        attributeMetadata.LogicalName)
                            };
                        Debug.WriteLine(String.Format("{0}.{1}", entity.LogicalName, attributeMetadata.LogicalName));
                    }
                }
            }
        }
    }
    #endregion

}
namespace.namespace
{
使用制度;
使用System.CodeDom;
使用系统诊断;
使用System.Linq;
使用Microsoft.Crm.Services.Utility;
使用Microsoft.Xrm.Sdk.Metadata;
/// 
///自定义代码dom服务。
/// 
公共密封类CustomizeCodeDomService:ICCustomizeCodeDomService
{
#区域常数和字段
/// 
///元数据。
/// 
私有组织元数据;
#端区
#区域属性
#端区
#区域公共方法
/// 
///自定义dom代码。
/// 
/// 
///代码编译单元。
/// 
/// 
///服务。
/// 
public void CustomizeCodeDom(CodeCompileUnit CodeCompileUnit,IServiceProvider服务)
{
//找到要使用的命名空间
CodeNamespace CodeNamespace=codeCompileUnit.Namespaces[0];
var metadataProviderService=(IMetadataProviderService)services.GetService(typeof(IMetadataProviderService));
var filterService=(ICodeWriterFilterService)services.GetService(typeof(ICodeWriterFilterService));
this.metadata=metadataProviderService.LoadMetadata();
foreach(此.metadata.Entities中的EntityMetadata EntityMetadata)
{
if(filterService.GenerateEntity(实体元数据、服务))
{
CodeTypeDeclaration实体类=
首先(codeType=>codeType.Name.ToUpper()==entityMetadata.SchemaName.ToUpper());
UpdateNumsetter(entityClass、entityMetadata);
}
}
}
#端区
#区域私有方法
私有静态void updatenumsetter(
代码类型声明实体类、实体元数据实体)
{
foreach(entity.Attributes.Where中的var attributeMetadata(attributeMetadata=>String.IsNullOrWhiteSpace(attributeMetadata.AttributeOf)))
{
//匹配相应的字段名。
AttributeMetadata元数据1=AttributeMetadata;
弗雷奇(
CodeTypeMember中的codeMembers
entityClass.Members.Cast()。其中(
codeMembers=>codeMembers.Name==metadata1.SchemaName))
{
var codeProperty=(CodeMemberProperty)codeMembers;
if(codeProperty.HasSet)
{
if(attributeMetadata.AttributeType!=null&&attributeMetadata.AttributeType.Value==AttributeTypeCode.Picklist)
{
((CodeConditionStatement)codeProperty.SetStatements[1]).FalseStatements[0]=
新代码片段语句
{
价值观=
字符串格式(
“this.SetAttributeValue(\“{0}\”,新的Microsoft.Xrm.Sdk.OptionSetValue(value.value));”,
attributeMetadata.LogicalName)
};
Debug.WriteLine(String.Format(“{0}.{1}”,entity.LogicalName,attributeMetadata.LogicalName));
}
}
}
}
}
#端区
}

}

我打赌Guarav的答案是真正可行的,但由于缺少关于
CRMSvcUtil
的文档,我不得不使用我的变通方法。(我使用一个单独的项目,在其中过滤我需要的实体,使用Erik建议的参数运行
CRMSvcUtil
,在生成文件后将代码中麻烦的部分
(int)(value)
(其中
value
是一个
OptionSetValue
)替换为
value.value
,然后重新保存文件。)

这不是一个完美的解决方案,但一直以来
namespace The.NameSpace
{
 using System;
 using System.CodeDom;
 using System.Diagnostics;
 using System.Linq;

 using Microsoft.Crm.Services.Utility;
 using Microsoft.Xrm.Sdk.Metadata;

/// <summary>
/// The customize code dom service.
/// </summary>
public sealed class CustomizeCodeDomService : ICustomizeCodeDomService
{
    #region Constants and Fields

    /// <summary>
    ///   The metadata.
    /// </summary>
    private IOrganizationMetadata metadata;

    #endregion

    #region Properties



    #endregion

    #region Public Methods

    /// <summary>
    /// The customize code dom.
    /// </summary>
    /// <param name="codeCompileUnit">
    /// The code compile unit.
    /// </param>
    /// <param name="services">
    /// The services.
    /// </param>
    public void CustomizeCodeDom(CodeCompileUnit codeCompileUnit, IServiceProvider services)
    {
        // Locate the namespace to use
        CodeNamespace codeNamespace = codeCompileUnit.Namespaces[0];

        var metadataProviderService = (IMetadataProviderService)services.GetService(typeof(IMetadataProviderService));
        var filterService = (ICodeWriterFilterService)services.GetService(typeof(ICodeWriterFilterService));

        this.metadata = metadataProviderService.LoadMetadata();

        foreach (EntityMetadata entityMetadata in this.metadata.Entities)
        {
            if (filterService.GenerateEntity(entityMetadata, services))
            {
                CodeTypeDeclaration entityClass =
                    codeNamespace.Types.Cast<CodeTypeDeclaration>().First(codeType => codeType.Name.ToUpper() == entityMetadata.SchemaName.ToUpper());

                UpdateEnumSetter(entityClass, entityMetadata);

            }
        }
    }

    #endregion

    #region Private Methods
    private static void UpdateEnumSetter(
  CodeTypeDeclaration entityClass, EntityMetadata entity)
    {
        foreach (var attributeMetadata in entity.Attributes.Where(attributeMetadata => String.IsNullOrWhiteSpace(attributeMetadata.AttributeOf)))
        {
            //Match the respective field Name. 
            AttributeMetadata metadata1 = attributeMetadata;
            foreach (
                CodeTypeMember codeMembers in
                    entityClass.Members.Cast<CodeTypeMember>().Where(
                        codeMembers => codeMembers.Name == metadata1.SchemaName))
            {
                var codeProperty = (CodeMemberProperty)codeMembers;

                if (codeProperty.HasSet)
                {
                    if (attributeMetadata.AttributeType != null && attributeMetadata.AttributeType.Value == AttributeTypeCode.Picklist)
                    {
                        ((CodeConditionStatement)codeProperty.SetStatements[1]).FalseStatements[0] =
                            new CodeSnippetStatement
                            {
                                Value =
                                    String.Format(
                                        "this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));",
                                        attributeMetadata.LogicalName)
                            };
                        Debug.WriteLine(String.Format("{0}.{1}", entity.LogicalName, attributeMetadata.LogicalName));
                    }
                }
            }
        }
    }
    #endregion

}
    private static void UpdateEnumSetter(CodeTypeDeclaration entityClass, EntityMetadata entity)
    {
        foreach (var attributeMetadata in entity.Attributes.Where(attributeMetadata => String.IsNullOrWhiteSpace(attributeMetadata.AttributeOf)))
        {
            AttributeMetadata currentMetadata = attributeMetadata;
            foreach (CodeTypeMember codeMembers in entityClass.Members.Cast<CodeTypeMember>().Where(codeMembers => codeMembers.Name == currentMetadata.SchemaName))
            {
                CodeMemberProperty codeProperty = (CodeMemberProperty)codeMembers;
                if (codeProperty.HasSet)
                {
                    if (attributeMetadata.AttributeType != null && (attributeMetadata.AttributeType.Value == AttributeTypeCode.Picklist || attributeMetadata.AttributeType.Value == AttributeTypeCode.Status))
                    {
                        if (codeProperty.SetStatements[1].GetType() == typeof(CodeConditionStatement))
                        {
                            ((CodeConditionStatement)codeProperty.SetStatements[1]).FalseStatements[0] = new CodeSnippetStatement
                            {
                                Value = String.Format("this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));", attributeMetadata.LogicalName)
                            };
                        }
                        else
                        {
                            codeProperty.SetStatements[1] = new CodeSnippetStatement(String.Format("this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));", attributeMetadata.LogicalName));
                        }
                    }
                }
            }
        }
    }
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("prioritycode")]
public Microsoft.Xrm.Sdk.OptionSetValue PriorityCode
{
    get
    {
        return this.GetAttributeValue<Microsoft.Xrm.Sdk.OptionSetValue>("prioritycode");
    }
    set
    {
        this.OnPropertyChanging("PriorityCode");
        this.SetAttributeValue("prioritycode", value);
        this.OnPropertyChanged("PriorityCode");
    }
}
public enum entityname_optionsetname 
{
    Value = 200
}

[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("myprefix_fieldname")]
public entityname_optionsetname myprefix_FieldName
{
    get
    {
        Microsoft.Xrm.Sdk.OptionSetValue optionSet = this.GetAttributeValue<Microsoft.Xrm.Sdk.OptionSetValue>("myprefix_fieldname");
        if ((optionSet != null))
        {
            return ((entityname_optionsetname)(System.Enum.ToObject(typeof(Microsoft.Xrm.Sdk.OptionSetValue), optionSet.Value)));
        }
        else
        {
            return null;
        }
    }
    set
    {
        this.OnPropertyChanging("myprefix_FieldName");
        if ((value == null))
        {
            this.SetAttributeValue("myprefix_fieldname", null);
        }
        else
        {
            this.SetAttributeValue("myprefix_fieldname", new Microsoft.Xrm.Sdk.OptionSetValue(((int)(value))));
        }
        this.OnPropertyChanged("myprefix_FieldName");
    }
}
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk.Metadata;
using System.Text.RegularExpressions;
using Microsoft.Xrm.Sdk;

namespace SvcUtilFilter
{
    /// <summary>
    /// CodeWriterFilter for CrmSvcUtil that reads list of entities from an xml file to
    /// determine whether or not the entity class should be generated.
    /// </summary>
    public class CodeWriterFilter : ICodeWriterFilterService
    {
        //list of entity names to generate classes for.
        private HashSet<string> _validEntities = new HashSet<string>();

        //reference to the default service.
        private ICodeWriterFilterService _defaultService = null;

        //list of generated option sets, instantiated in the constructor
        private List<string> GeneratedOptionSets;

        //list of generated options, instantiated in the constructor
        private List<string> GeneratedOptions;

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="defaultService">default implementation</param>
        public CodeWriterFilter(ICodeWriterFilterService defaultService)
        {
            this._defaultService = defaultService;
            this.GeneratedOptionSets = new List<string>();
            this.GeneratedOptions = new List<string>();
            LoadFilterData();
        }

        /// <summary>
        /// loads the entity filter data from the filter.xml file
        /// </summary>
        private void LoadFilterData()
        {
            XElement xml = XElement.Load("filter.xml");
            XElement entitiesElement = xml.Element("entities");
            foreach (XElement entityElement in entitiesElement.Elements("entity")) {
                _validEntities.Add(entityElement.Value.ToLowerInvariant());
            }
        }

        /// <summary>
        /// /Use filter entity list to determine if the entity class should be generated.
        /// </summary>
        public bool GenerateEntity(EntityMetadata entityMetadata, IServiceProvider services)
        {
            return (_validEntities.Contains(entityMetadata.LogicalName.ToLowerInvariant()));
        }

        //All other methods just use default implementation:

        public bool GenerateAttribute(AttributeMetadata attributeMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateAttribute(attributeMetadata, services);
        }

        public bool GenerateOption(OptionMetadata optionMetadata, IServiceProvider services)
        {
            //return _defaultService.GenerateOption(optionMetadata, services);
            string label = optionMetadata.Label.UserLocalizedLabel.Label;

            //remove spaces and special characters
            label = Regex.Replace(label, @"[^a-zA-Z0-9]", string.Empty);
            if (label.Length > 0 && !char.IsLetter(label, 0)) {
                label = "Number_" + label;
            }
            else if (label.Length == 0) {
                label = "empty";
            }

            if (!GeneratedOptions.Exists(l=>l.Equals(label))) {
                GeneratedOptions.Add(label);
                optionMetadata.Label = new Label(label, 1033);
                return _defaultService.GenerateOption(optionMetadata, services);
            }
            else { return false; }
        }

        public bool GenerateOptionSet(OptionSetMetadataBase optionSetMetadata, IServiceProvider services)
        {
            //return _defaultService.GenerateOptionSet(optionSetMetadata, services);
            if (!GeneratedOptionSets.Contains(optionSetMetadata.Name)) {
                GeneratedOptionSets.Add(optionSetMetadata.Name);
                return true;
            }

            return _defaultService.GenerateOptionSet(optionSetMetadata, services);
        }

        public bool GenerateRelationship(RelationshipMetadataBase relationshipMetadata, EntityMetadata otherEntityMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateRelationship(relationshipMetadata, otherEntityMetadata, services);
        }

        public bool GenerateServiceContext(IServiceProvider services)
        {
            return _defaultService.GenerateServiceContext(services);
        }
    }
}
using System;
using System.CodeDom;
using System.Diagnostics;
using System.Linq;

using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk.Metadata;

namespace SvcUtilFilter
{
    /// <summary>
    /// The customize code dom service.
    /// </summary>
    public sealed class CustomizeCodeDomService : ICustomizeCodeDomService
    {
        #region Constants and Fields

        /// <summary>
        ///   The metadata.
        /// </summary>
        private IOrganizationMetadata metadata;

        #endregion

        #region Properties



        #endregion

        #region Public Methods

        /// <summary>
        /// The customize code dom.
        /// </summary>
        /// <param name="codeCompileUnit">
        /// The code compile unit.
        /// </param>
        /// <param name="services">
        /// The services.
        /// </param>
        public void CustomizeCodeDom(CodeCompileUnit codeCompileUnit, IServiceProvider services)
        {
            // Locate the namespace to use
            CodeNamespace codeNamespace = codeCompileUnit.Namespaces[0];

            var metadataProviderService = (IMetadataProviderService)services.GetService(typeof(IMetadataProviderService));
            var filterService = (ICodeWriterFilterService)services.GetService(typeof(ICodeWriterFilterService));

            this.metadata = metadataProviderService.LoadMetadata();

            foreach (EntityMetadata entityMetadata in this.metadata.Entities) {
                if (filterService.GenerateEntity(entityMetadata, services)) {
                    CodeTypeDeclaration entityClass =
                        codeNamespace.Types.Cast<CodeTypeDeclaration>().First(codeType => codeType.Name.ToUpper() == entityMetadata.SchemaName.ToUpper());

                    UpdateEnumSetter(entityClass, entityMetadata);

                }
            }
        }

        #endregion

        #region Private Methods
        private static void UpdateEnumSetter(CodeTypeDeclaration entityClass, EntityMetadata entity)
        {
            foreach (var attributeMetadata in entity.Attributes.Where(attributeMetadata => String.IsNullOrWhiteSpace(attributeMetadata.AttributeOf))) {
                AttributeMetadata currentMetadata = attributeMetadata;
                foreach (CodeTypeMember codeMembers in entityClass.Members.Cast<CodeTypeMember>().Where(codeMembers => codeMembers.Name == currentMetadata.SchemaName)) {
                    CodeMemberProperty codeProperty = (CodeMemberProperty)codeMembers;
                    if (codeProperty.HasSet) {
                        if (attributeMetadata.AttributeType != null && (attributeMetadata.AttributeType.Value == AttributeTypeCode.Picklist || attributeMetadata.AttributeType.Value == AttributeTypeCode.Status)) {
                            if (codeProperty.SetStatements[1].GetType() == typeof(CodeConditionStatement)) {
                                ((CodeConditionStatement)codeProperty.SetStatements[1]).FalseStatements[0] = new CodeSnippetStatement {
                                    Value = String.Format("this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));", attributeMetadata.LogicalName)
                                };
                            }
                            else {
                                codeProperty.SetStatements[1] = new CodeSnippetStatement(String.Format("this.SetAttributeValue(\"{0}\", new Microsoft.Xrm.Sdk.OptionSetValue(value.Value));", attributeMetadata.LogicalName));
                            }
                        }
                    }
                }
            }
        }
        #endregion
    }
}
@echo off

set url=https://[organization].api.crm.dynamics.com/XRMServices/2011/Organization.svc

echo.
echo Generating CrmSvcUtil Proxy class in output folder
echo.

CrmSvcUtil.exe /metadataproviderservice:"MetadataProvider.IfdMetadataProviderService, 
MetadataProvider" 
/url:https://[organization].api.crm.dynamics.com/XRMServices/2011/Organization.svc /out:Xrm.cs 
/namespace:Xrm /serviceContextName:XrmServiceContext /serviceContextPrefix:Xrm 
/u:[username] /p:[password] 
/codewriterfilter:SvcUtilFilter.CodeWriterFilter,SvcUtilFilter 
/codecustomization:SvcUtilFilter.CustomizeCodeDomService,SvcUtilFilter

echo.
pause
<filter>
  <entities>
    <entity>systemuser</entity>
    <entity>team</entity>
    <entity>role</entity>
    <entity>businessunit</entity>
    <entity>account</entity>
    <entity>product</entity>
    <entity>transactioncurrency</entity>
  </entities>
</filter>