如何使用EntityMetadata将查找属性复制到另一个CRM?

时间:2019-01-10 17:30:17

标签: c# dynamics-crm microsoft-dynamics

我正在尝试将一个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;
                            }
                        }
                    }
                }
            }
        }

1 个答案:

答案 0 :(得分:1)

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

此代码反映了其中的一些想法,下面提供了更多信息。

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标志重置为false,并将其IsCustomizable的值重置为true。 isManaged isCustomizable
  3. 一旦您手动将解决方案的关系创建为非托管关系,您将永远无法在该系统中安装托管解决方案。因此,我想知道从长远来看,通过代码创建托管查找字段是否是一种好习惯?为什么不将托管解决方案安装在迁移目标系统中呢?
  4. 在尝试复制1:N关系之前,您可能希望尝试从头开始在代码中创建一个关系,以查看真正需要什么信息。这可以帮助您将要检索的内容减少到创建一个所需内容的最低限度。例如,属性的ColumnNumber是只读的,而下载的数据具有该属性。如果您是从头开始创建新的属性,则应为空白。
  5. 从长远来看,这种方法可能会变得麻烦多于其应有的价值。就像您的组织开始使用更多的沙盒环境,并且每次都要设置代码时都必须运行代码。也许重新考虑使用解决方案,或者采用一种混合方法,即通过解决方案在代码中创建一些查找,其余的通过查找来解决。