首页 > 解决方案 > 如何使用 EntityMetadata 将查找属性复制到另一个 CRM?

问题描述

我正在尝试将 CRM 的查找字段复制到另一个 CRM。但这失败了,因为通常我得到一个异常,说具有查找逻辑名称的属性不存在。

好的,我知道,因为我正在尝试创建它。当这种情况发生时,关系的引用属性是查找,所以查找必须在被引用的属性中。

但是我尝试搜索在引用属性中具有查找逻辑名称的关系,但我没有找到,我尝试了两个实体的 OneToMany 和 ManyToOne。所以我需要帮助来解决这个问题。有人有解决方案吗?

我不想使用解决方案解决此问题,因为解决方案无法复制托管查找字段。我拥有要在另一个 CRM 中创建的所有属性和实体,我只需要创建查找和您的关系。

我有这个基本代码,但需要 2 个 CRM 来测试它。

public void CopyLookup() {

        List<EntityMetadata> OriginEntities = new List<EntityMetadata>();

        bool sucess = false;

        while (!sucess) {
            try {

                RetrieveAllEntitiesRequest metaDataRequest = new RetrieveAllEntitiesRequest();
                metaDataRequest.EntityFilters = EntityFilters.All;

                // Execute the request.

                RetrieveAllEntitiesResponse metaDataResponse = (RetrieveAllEntitiesResponse)Origin.IOrganizationService.Execute(metaDataRequest);
                OriginEntities = new List<EntityMetadata>(metaDataResponse.EntityMetadata);
                sucess = true;
                return entitiesMetadata;

            } catch (ThreadAbortException) {
            } catch (Exception _ex) {
                Console.WriteLine(String.Format("Fail to find Entities - {0}", _ex.Message));
                if (_ex.Message.Contains("There was no endpoint"))
                    sucess = false;
                else
                    throw new Exception(String.Format("Fail to find Entities - {0}", _ex.Message));
            }
        }


        foreach (EntityMetadata ent in OriginEntities.Where(wh => wh.LogicalName.Contains('_'))) {

                foreach (OneToManyRelationshipMetadata relation in ent.OneToManyRelationships) {

                    LookupAttributeMetadata lookup = (LookupAttributeMetadata)OriginEntities.Where(wh => relation.ReferencingEntity == wh.LogicalName).FirstOrDefault()
                                                                             .Attributes.Where(wa => wa.AttributeType == AttributeTypeCode.Lookup && wa.LogicalName == relation.ReferencingAttribute).FirstOrDefault();

                    if (lookup == null)
                        continue;

                    CreateOneToManyRequest createOtm = new CreateOneToManyRequest() {
                        OneToManyRelationship = relation,
                        Lookup = lookup
                    };

                    bool sucess2 = false;

                    while (!sucess2) {

                        try {
                            Migration.IOrganizationService.Execute(createOtm);
                        } catch (EndpointNotFoundException) {
                            sucess2 = false;
                        } catch (TimeoutException) {
                            sucess2 = false;
                        } catch (FaultException ex) {
                            if (ex.Message.Contains("endpoint")) {
                                sucess2 = false;
                            } else if (ex.Message.Contains("there is already")) {
                                sucess2 = true;
                            } else {
                                sucess2 = true;
                            }
                        } catch (Exception ex) {
                            if (ex.Message.Contains("This could be due to the service endpoint binding")) {
                                sucess2 = false;
                            } else if (ex.Message.Contains("is not unique")) {
                                sucess2 = true;
                            } else {
                                sucess2 = true;
                            }
                        }
                    }
                }
            }
        }

标签: c#dynamics-crmmicrosoft-dynamics

解决方案


我总是手动或通过解决方案创建关系,但我查看了您的代码并得到了一些可能有帮助的想法......

此代码反映了其中一些想法,更多信息如下。

var metaDataRequest = new RetrieveAllEntitiesRequest
{
    EntityFilters = EntityFilters.All
};

var metaDataResponse = (RetrieveAllEntitiesResponse)svc.Execute(metaDataRequest);
var OriginEntities = metaDataResponse.EntityMetadata.ToList();

foreach (var entity in OriginEntities.Where(e=> e.IsCustomizable.Value))
{
    foreach (var relationship in entity.OneToManyRelationships.Where(r => r.IsCustomRelationship == true))
    {
        var lookup = OriginEntities
            .Where(e => e.LogicalName == relationship.ReferencingEntity)
            .Single()
            .Attributes
            .Where(a => a.AttributeType == AttributeTypeCode.Lookup && a.LogicalName == relationship.ReferencingAttribute)
            .Single();
        var createOtm = new CreateOneToManyRequest()
        {
            OneToManyRelationship = relationship,
            Lookup = lookup as LookupAttributeMetadata
        };
    }
}
  1. 我认为您只想处理可自定义的实体以及它们上的自定义关系,这就是我修改循环中的Where子句的原因。foreach
  2. 如果您要创建托管查找字段的副本,我认为您需要将关系的IsManaged标志重置为 true,false并将其IsCustomizable值重置为 true。 是托管的 是可定制的
  3. 一旦您手动将解决方案的关系创建为非托管,您将永远无法在该系统中安装托管解决方案。所以,我想知道通过代码创建托管查找字段是否是长期的好习惯。为什么不在迁移目标系统中安装托管解决方案呢?
  4. 在尝试复制 1:N 关系之前,您可能想尝试在代码中从头开始创建一个关系,以查看真正需要哪些信息。这可以帮助您将要检索的内容减少到创建所需内容的最低限度。比如一个Attribute的ColumnNumber是只读的,下载的数据有它。如果您从头开始创建新属性,则该属性应为空白。
  5. 从长远来看,这种方法可能会变得比它的价值更麻烦。就像您的组织开始使用更多沙盒环境,并且您每次想要设置一个时都必须运行代码。也许重新考虑使用解决方案,或者采用混合方法在代码中创建一些查找,其余部分通过解决方案。

推荐阅读