Ejemplo n.º 1
0
        private void SaveWorkItem(OAdEntity entity)
        {
            string retVal = CQWrapper.Validate(entity);

            Trace.WriteIf(!string.IsNullOrEmpty(retVal), "retVal = " + retVal);
            Assert.IsTrue(string.IsNullOrEmpty(retVal), "retVal is not empty after validate");

            retVal = CQWrapper.Commmit(entity);
            Trace.WriteIf(!string.IsNullOrEmpty(retVal), "retVal = " + retVal);
            Assert.IsTrue(string.IsNullOrEmpty(retVal), "retVal is not empty after commit");
        }
        public bool Update(
            ClearQuestMigrationContext migrationContext,
            Session cqSession,
            OAdEntity hostRecord,
            LinkChangeAction linkChangeAction)
        {
            if (null == linkChangeAction)
            {
                throw new ArgumentNullException("linkChangeAction");
            }

            if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(REFERENCE_NAME))
            {
                throw new ArgumentException("Link type mismatch.");
            }

            string childRecEntityDefName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDefName(linkChangeAction.Link.TargetArtifact,
                                                                         out childRecEntityDefName))
            {
                return(false);
            }
            string childRecDispName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(linkChangeAction.Link.TargetArtifact,
                                                                          out childRecDispName))
            {
                return(false);
            }

            OAdEntity childEntity = CQWrapper.GetEntity(cqSession, childRecEntityDefName, childRecDispName);

            if (null == childEntity)
            {
                return(false);
            }

            // check if hostRecord already has a duplicate of this childRecord
            bool duplicateAlreadyExist = HasDuplicateRecord(hostRecord, childRecEntityDefName, childRecDispName);

            // find out the child entity's current state
            // find the current state
            string childEntityDefName = CQWrapper.GetEntityDefName(childEntity);

            OAdFieldInfo aFldInfo       = CQWrapper.GetEntityFieldValue(childEntity, migrationContext.GetStateField(childEntityDefName));
            string       srcState       = CQWrapper.GetFieldValue(aFldInfo);
            OAdEntityDef childEntityDef = CQWrapper.GetEntityDef(cqSession, childEntityDefName);

            if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add))
            {
                if (duplicateAlreadyExist)
                {
                    // [teyang] TODO
                    return(false);
                }

                string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState(
                    childEntityDef,
                    srcState,
                    CQConstants.ACTION_DUPLICATE);

                string changeActionName = string.Empty;
                if (changeActionNames.Length == 0)
                {
                    // [teyang] TODO conflict
                }
                else if (changeActionNames.Length > 1)
                {
                    // [teyang] TODO conflict
                }
                else
                {
                    changeActionName = changeActionNames[0];
                }

                if (!string.IsNullOrEmpty(changeActionName))
                {
                    CQWrapper.MarkEntityAsDuplicate(cqSession, childEntity, hostRecord, changeActionName);

                    string retVal = CQWrapper.Validate(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }

                    retVal = CQWrapper.Commmit(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }
                }
            }
            else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete))
            {
                if (!duplicateAlreadyExist)
                {
                    // [teyang] TODO
                    return(false);
                }

                string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState(
                    childEntityDef,
                    srcState,
                    CQConstants.ACTION_UNDUPLICATE);

                string changeActionName = string.Empty;
                if (changeActionNames.Length == 0)
                {
                    // [teyang] TODO conflict
                }
                else if (changeActionNames.Length > 1)
                {
                    // [teyang] TODO conflict
                }
                else
                {
                    changeActionName = changeActionNames[0];
                }

                if (!string.IsNullOrEmpty(changeActionName))
                {
                    CQWrapper.UnmarkEntityAsDuplicate(cqSession, childEntity, changeActionName);

                    string retVal = CQWrapper.Validate(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }

                    retVal = CQWrapper.Commmit(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }
                }
            }
            else
            {
                //throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction);
            }

            return(true);
        }
        private void AddRecord(IMigrationAction action, ConversionResult convRslt)
        {
            string    recordType = UtilityMethods.ExtractRecordType(action);
            OAdEntity newRecord  = CQWrapper.BuildEntity(m_userSession, recordType);

            string        validationRsltString = string.Empty;
            List <string> processedFields      = new List <string>();

            #region add new record with MANDATORY field values

            if (!SetMandatoryFields(action, ref newRecord, out processedFields))
            {
                return;
            }

            bool unResolvedConflictExists = false;
            bool validationErrorExists    = false;
            validationRsltString = CQWrapper.Validate(newRecord);
            if (!string.IsNullOrEmpty(validationRsltString))
            {
                validationErrorExists = true;
                IEnumerable <CQTextParser.RecordValidationResult> validationResults;
                if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults))
                {
                    foreach (CQTextParser.RecordValidationResult rslt in validationResults)
                    {
                        MigrationConflict      conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                        List <MigrationAction> actions;
                        var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            unResolvedConflictExists = true;
                            break;
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException(validationRsltString);
                }
            }

            if (unResolvedConflictExists)
            {
                return;
            }
            else if (validationErrorExists)
            {
                // All conflicts are resolved. Try re-applying the changes
                newRecord.Revert();

                SetRecordEditable(newRecord);

                if (!SetMandatoryFields(action, ref newRecord, out processedFields))
                {
                    return;
                }
                else
                {
                    validationRsltString = CQWrapper.Validate(newRecord);
                    if (!string.IsNullOrEmpty(validationRsltString))
                    {
                        IEnumerable <CQTextParser.RecordValidationResult> validationResults;
                        if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults) &&
                            validationResults.Count() > 0)
                        {
                            CQTextParser.RecordValidationResult rslt = validationResults.First();
                            MigrationConflict conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                            m_conflictManagerService.BacklogUnresolvedConflict(m_conflictManagerService.SourceId, conflict, false);
                            return;
                        }
                        else
                        {
                            throw new InvalidOperationException(validationRsltString);
                        }
                    }
                }
            }


            validationRsltString = CQWrapper.Commmit(newRecord);
            if (!string.IsNullOrEmpty(validationRsltString))
            {
                // [teyang] TODO: invalid update conflict handling
                throw new InvalidOperationException(validationRsltString);
            }

            string newRecordDisplayName = CQWrapper.GetEntityDisplayName(newRecord);
            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            UpdateConversionHistory(action, newRecordDisplayName, ClearQuestRecordItem.NewRecordVersion, convRslt);
            #endregion

            #region update the new record with remaining field values
            ModifyRecordContent(newRecord, action, convRslt, processedFields);
            #endregion
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="action"></param>
        /// <param name="convRslt"></param>
        /// <param name="stateTransitFieldNode"></param>
        /// <param name="skipFields"></param>
        /// <returns></returns>
        private bool ChangeRecordState(
            OAdEntity entity,
            IMigrationAction action,
            ConversionResult convRslt,
            XmlNode stateTransitFieldNode,
            out List <string> processedFields)
        {
            processedFields = new List <string>();

            string destState = UtilityMethods.ExtractSingleFieldValue(stateTransitFieldNode);

            Debug.Assert(!string.IsNullOrEmpty(destState), "string.IsNullOrEmpty(newState)");

            // get the record's display name for updating conversion history
            string recordDisplayName = CQWrapper.GetEntityDisplayName(entity);

            string entityDefName = CQWrapper.GetEntityDefName(entity);

            // find the current state
            OAdFieldInfo aFldInfo = CQWrapper.GetEntityFieldValue(entity, m_migrationContext.GetStateField(entityDefName));
            string       srcState = CQWrapper.GetFieldValue(aFldInfo);

            if (CQStringComparer.StateName.Equals(srcState, destState))
            {
                // state does not change, skip this action
                return(false);
            }

            // find action def name
            OAdEntityDef entityDef = CQWrapper.GetEntityDef(m_userSession, entityDefName);

            string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndStateTransition(entityDef, srcState, destState, CQConstants.ACTION_CHANGE);

            if (changeActionNames.Length == 0)
            {
                // [teyang] todo error handling
                throw new InvalidOperationException();
            }

            string changeActionName = changeActionNames[0];

            // *********
            // cache the current history count for all "history fields"
            // i.e. pairs of HistoryFieldName, count
            Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();

            BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

            StringBuilder updateLog = new StringBuilder();

            PrintUpdateLogHeader(action, updateLog);

            // mark entity to be editable with the desired state-change action)
            CQWrapper.EditEntity(m_userSession, entity, changeActionName);

            XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column");

            if (null == columns)
            {
                throw new MigrationException(ClearQuestResource.ClearQuest_Error_InvalidActionDescription, action.ActionId);
            }

            foreach (XmlNode columnData in columns)
            {
                string stringVal = columnData.FirstChild.InnerText;
                string fieldName = columnData.Attributes["ReferenceName"].Value;

                Debug.Assert(!string.IsNullOrEmpty(fieldName),
                             "Field ReferenceName is absent in the Migration Description");


                OAdFieldInfo aFieldInfo        = CQWrapper.GetEntityFieldValue(entity, fieldName);
                int          fieldRequiredness = CQWrapper.GetRequiredness(aFieldInfo);
                if (fieldRequiredness != CQConstants.MANDATORY)
                {
                    // skipping all non-mandatory fields
                    continue;
                }

                int attempt1Count = 0;
                if (!SetFieldValue(action, entity, fieldName, stringVal, ref attempt1Count))
                {
                    return(false);
                }
                AddFieldToUpdateLog(fieldName, stringVal, updateLog);
                processedFields.Add(fieldName);
            }

            AddLineToUpdateLog(updateLog);
            int attempt2Count = 0;

            if (!SetFieldValue(action, entity, NoteEntryFieldName, updateLog.ToString(), ref attempt2Count))
            {
                return(false);
            }

            string retVal = CQWrapper.Validate(entity);

            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO conflict handling
                throw new InvalidOperationException(retVal);
            }

            retVal = CQWrapper.Commmit(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO conflict handling
                throw new InvalidOperationException(retVal);
            }

            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            // *********
            // now comparing to the cache, so that we can clearly identify the item:version pairs
            // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
            Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();

            FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
            recordHistoryCountCache.Clear();

            foreach (string histFieldName in updatedHistoryIndices.Keys)
            {
                foreach (int histIndex in updatedHistoryIndices[histFieldName])
                {
                    UpdateConversionHistory(action,
                                            recordDisplayName,
                                            CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                            convRslt);
                }
            }

            return(true);
        }
        private void ModifyRecordContent(
            OAdEntity entity,
            IMigrationAction action,
            ConversionResult convRslt,
            List <string> skipFields)
        {
            XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column");

            if (null == columns)
            {
                throw new MigrationException(ClearQuestResource.ClearQuest_Error_InvalidActionDescription, action.ActionId);
            }

            // get the record's display name for updating conversion history
            string recordDisplayName = CQWrapper.GetEntityDisplayName(entity);

            // *********
            // cache the current history count for all "history fields"
            // i.e. pairs of HistoryFieldName, count
            Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();

            BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

            SetRecordEditable(entity);

            StringBuilder updateLog = new StringBuilder();

            PrintUpdateLogHeader(action, updateLog);

            string entityDefName = CQWrapper.GetEntityDefName(entity);
            string stateTransitionFieldDefName = m_migrationContext.GetStateField(entityDefName);

            string retVal;
            bool   recordIsUpdated = false;

            foreach (XmlNode columnData in columns)
            {
                string stringVal = columnData.FirstChild.InnerText;
                string fieldName = columnData.Attributes["ReferenceName"].Value;
                Debug.Assert(!string.IsNullOrEmpty(fieldName),
                             "Field ReferenceName is absent in the Migration Description");

                if (CQStringComparer.FieldName.Equals(fieldName, stateTransitionFieldDefName) ||
                    (null != skipFields && skipFields.Contains(fieldName, CQStringComparer.FieldName)))
                {
                    // skip or "State" field, as it has already been submitted in a separate history/revision
                    continue;
                }

                bool         setFieldValue     = false;
                OAdFieldInfo aFieldInfo        = CQWrapper.GetEntityFieldValue(entity, fieldName);
                int          fieldRequiredness = CQWrapper.GetRequiredness(aFieldInfo);
                switch (fieldRequiredness)
                {
                case CQConstants.MANDATORY:
                case CQConstants.OPTIONAL:
                    setFieldValue = true;
                    break;

                case CQConstants.READONLY:
                    // [teyang] TODO conflict handling
                    TraceManager.TraceWarning("Field {0} is READONLY", fieldName);
                    setFieldValue = false;
                    break;

                case CQConstants.USEHOOK:
                    // [teyang] TODO conflict handling
                    TraceManager.TraceWarning("Field {0} is USEHOOK", fieldName);
                    setFieldValue = false;
                    break;

                default:
                    throw new InvalidOperationException();
                }

                if (setFieldValue)
                {
                    int attempt1Count = 0;
                    if (!SetFieldValue(action, entity, fieldName, stringVal, ref attempt1Count))
                    {
                        return;
                    }
                    AddFieldToUpdateLog(fieldName, stringVal, updateLog);
                    recordIsUpdated = true;
                }
            }

            if (!recordIsUpdated)
            {
                // no update has been made to the record, mark this action to be skipped
                CQWrapper.Revert(entity);
                if (action.State == ActionState.Pending)
                {
                    action.State = ActionState.Skipped;
                }

                return;
            }

            AddLineToUpdateLog(updateLog);
            int attempt2Count = 0;

            if (!SetFieldValue(action, entity, NoteEntryFieldName, updateLog.ToString(), ref attempt2Count))
            {
                return;
            }

            retVal = CQWrapper.Validate(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                IEnumerable <Microsoft.TeamFoundation.Migration.ClearQuestAdapter.CQTextParser.RecordValidationResult> validationResults;
                if (CQTextParser.RecordValidationTextParser.TryParse(retVal, out validationResults))
                {
                    foreach (CQTextParser.RecordValidationResult rslt in validationResults)
                    {
                        MigrationConflict      conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                        List <MigrationAction> actions;
                        var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            action.ChangeGroup.ContainsBackloggedAction = true;
                            return;
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException(retVal);
                }
            }

            retVal = CQWrapper.Commmit(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO: invalid update conflict handling
                throw new InvalidOperationException(retVal);
            }

            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            // *********
            // now comparing to the cache, so that we can clearly identify the item:version pairs
            // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
            Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();

            FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
            recordHistoryCountCache.Clear();

            foreach (string histFieldName in updatedHistoryIndices.Keys)
            {
                foreach (int histIndex in updatedHistoryIndices[histFieldName])
                {
                    UpdateConversionHistory(action,
                                            recordDisplayName,
                                            CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                            convRslt);
                }
            }
        }
        private void AddAttachment(IMigrationAction action, ConversionResult convRslt)
        {
            string attName                = UtilityMethods.ExtractAttachmentName(action);
            string lengthStr              = UtilityMethods.ExtractAttachmentLength(action);
            string attComment             = UtilityMethods.ExtractAttachmentComment(action);
            string ownerRecordDisplayName = FindTargetWorkItemId(action);
            string ownerRecordType        = UtilityMethods.ExtractRecordType(action);

            string filePath = Path.Combine(m_configurationService.WorkspaceRoot,
                                           ownerRecordDisplayName + attName);

            try
            {
                // find the entity
                OAdEntity entity = CQWrapper.GetEntity(m_userSession, ownerRecordType, ownerRecordDisplayName);

                if (AttachmentExists(entity, attName, attComment, lengthStr))
                {
                    action.State = ActionState.Skipped;
                    return;
                }


                // find the change action def name
                string       entityDefName = CQWrapper.GetEntityDefName(entity);
                OAdEntityDef entityDef     = CQWrapper.GetEntityDef(m_userSession, entityDefName);

                string modifyActionDefName = FindCQActionDefName(entityDef, CQConstants.ACTION_MODIFY);

                // mark entity to be editable
                CQWrapper.EditEntity(m_userSession, entity, modifyActionDefName);

                // cache the current history count for all "history fields"
                // i.e. pairs of HistoryFieldName, count
                Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();
                BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

                action.SourceItem.Download(filePath);

                string attachmentField = m_migrationContext.GetAttachmentSinkField(entityDefName);
                string retVal          = CQWrapper.AddAttachmentFieldValue(entity, attachmentField, attName, filePath);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // teyang_todo attachment conflict
                }

                retVal = CQWrapper.Validate(entity);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict management
                    throw new InvalidOperationException();
                }

                retVal = CQWrapper.Commmit(entity);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict management
                    throw new InvalidOperationException();
                }

                if (action.State == ActionState.Pending)
                {
                    action.State = ActionState.Complete;
                }

                // *********
                // now comparing to the cache, so that we can clearly identify the item:version pairs
                // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
                Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();
                FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
                recordHistoryCountCache.Clear();

                foreach (string histFieldName in updatedHistoryIndices.Keys)
                {
                    foreach (int histIndex in updatedHistoryIndices[histFieldName])
                    {
                        UpdateConversionHistory(action,
                                                ownerRecordDisplayName,
                                                CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                                convRslt);
                    }
                }
            }
            finally
            {
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
        }
        public bool Update(
            ClearQuestMigrationContext migrationContext,
            Session session,
            OAdEntity hostRecord,
            LinkChangeAction linkChangeAction)
        {
            if (null == linkChangeAction)
            {
                throw new ArgumentNullException("linkChangeAction");
            }

            if (!linkChangeAction.Link.LinkType.ReferenceName.StartsWith(ReferenceNameQualifier))
            {
                throw new ArgumentException("Link type mismatch.");
            }

            string childRecEntityDefName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDefName(linkChangeAction.Link.TargetArtifact,
                                                                         out childRecEntityDefName))
            {
                return(false);
            }
            string childRecDispName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(linkChangeAction.Link.TargetArtifact,
                                                                          out childRecDispName))
            {
                return(false);
            }

            string hostRecEntityDefName = CQWrapper.GetEntityDefName(hostRecord);

            if (string.IsNullOrEmpty(hostRecEntityDefName) ||
                !CQStringComparer.EntityName.Equals(hostRecEntityDefName, this.m_hostRecordType))
            {
                return(false);
            }

            string refFieldName = linkChangeAction.Link.LinkType.ReferenceName.Substring(ReferenceNameQualifier.Length);

            if (string.IsNullOrEmpty(refFieldName))
            {
                return(false);
            }

            // retrieve reference field information
            OAdFieldInfo refFieldInfo = CQWrapper.GetEntityFieldValue(hostRecord, refFieldName);
            int          cqFieldType  = CQWrapper.GetFieldType(refFieldInfo);

            if (cqFieldType != CQConstants.FIELD_REFERENCE)
            {
                // the field is not of the reference type

                // [teyang] TODO conflict?
                return(false);
            }

            // get the current entity def
            OAdEntityDef hostRecordEntityDef      = CQWrapper.GetEntityDef(session, CQWrapper.GetEntityDefName(hostRecord));
            OAdEntityDef childRecordEntityDef     = CQWrapper.GetFieldReferenceEntityDef(hostRecordEntityDef, refFieldName);
            string       childRecordEntityDefName = CQWrapper.GetEntityDefName(childRecordEntityDef);

            if (!CQStringComparer.EntityName.Equals(childRecordEntityDefName, childRecEntityDefName))
            {
                // the field is not designated to hold reference to the EntityType of the target artifact

                // [teyang] TODO conflict?
                return(false);
            }

            int valueStatus = CQWrapper.GetFieldValueStatus(refFieldInfo);

            if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE)
            {
                // the field already has a reference value set

                // single value required
                string refFldVal = CQWrapper.GetFieldValue(refFieldInfo);
                if (CQStringComparer.RecordName.Equals(refFldVal, childRecDispName))
                {
                    // the target artifact is already referenced in the field

                    // [teyang] TODO conflict?
                    return(false);
                }
                else
                {
                    // field currently holds a reference to another entity

                    // [teyang] TODO conflict?
                    return(false);
                }
            }

            string[] modifyActionNames = CQUtilityMethods.FindAllChangeActionNamesByType(
                session, hostRecord, CQConstants.ACTION_MODIFY);

            if (modifyActionNames.Length == 0)
            {
                // [teyang] TODO conflict?
                return(false);
            }
            else if (modifyActionNames.Length > 1)
            {
                // [teyang] TODO conflict?
                return(false);
            }
            else
            {
                string modAction = modifyActionNames[0];

                CQWrapper.EditEntity(session, hostRecord, modAction);

                string retVal = CQWrapper.SetFieldValue(hostRecord, refFieldName, childRecDispName);

                retVal = CQWrapper.Validate(hostRecord);
                if (string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict
                    return(false);
                }

                retVal = CQWrapper.Commmit(hostRecord);
                if (string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict
                    return(false);
                }

                return(true);
            }
        }