/// <summary>
        /// Flatten an owned object and add an appropriate objsur to the specified property of the owning object.
        /// </summary>
        internal static void FlattenOwnedObject(string pathname,
                                                SortedDictionary <string, XElement> sortedData,
                                                XElement element, string ownerguid, XContainer owningElement, string propertyName)
        {
            FlattenObjectCore(pathname, sortedData, element, ownerguid);
            // We MUST create the objsur AFTER flattening the object, which may pathologically change its guid.
            var guid = element.Attribute(SharedConstants.GuidStr).Value.ToLowerInvariant();

            BaseDomainServices.RestoreObjsurElement(owningElement, propertyName, BaseDomainServices.CreateObjSurElement(guid));
        }
        private static void FlattenObjectCore(
            string pathname,
            SortedDictionary <string, XElement> sortedData,
            XElement element, string ownerguid)
        {
            if (string.IsNullOrEmpty(pathname))
            {
                throw new ArgumentNullException("pathname");
            }
            if (sortedData == null)
            {
                throw new ArgumentNullException("sortedData");
            }
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            // No, since unowned stuff will feed a null.
            //if (string.IsNullOrEmpty(ownerguid)) throw new ArgumentNullException(SharedConstants.OwnerGuid);
            if (ownerguid != null && ownerguid == string.Empty)
            {
                throw new ArgumentException(Resources.kOwnerGuidEmpty, SharedConstants.OwnerGuid);
            }

            string className;
            bool   isOwnSeqNode;
            var    elementGuid = CheckForDuplicateElementMethod.CheckForDuplicateGuid(pathname, sortedData, element, out isOwnSeqNode, out className);

            sortedData.Add(elementGuid, element);

            // The name of 'element' is the class of CmObject, or 'ownseq', or....
            element.Name = SharedConstants.RtTag;
            if (!isOwnSeqNode)
            {
                element.Add(new XAttribute(SharedConstants.Class, className));
            }
            //if (element.Attribute(SharedConstants.OwnerGuid) == null)
            if (ownerguid != null)             // && element.Attribute(SharedConstants.OwnerGuid) == null)
            {
                element.Add(new XAttribute(SharedConstants.OwnerGuid, ownerguid));
            }

            // Re-sort those attributes.
            var sortedAttrs = new SortedDictionary <string, XAttribute>();

            foreach (var attribute in element.Attributes())
            {
                sortedAttrs.Add(attribute.Name.LocalName, attribute);
            }
            element.Attributes().Remove();
            element.Add(sortedAttrs.Values);

            // Restore any ref seq props to have 'objsur' elements.
            var mdc             = MetadataCache.MdCache;
            var propCache       = mdc.PropertyCache[className];
            var refSeqPropNames = propCache["AllReferenceSequence"];
            // Restore any ref col props to have 'objsur' elements.
            var refColPropNames     = propCache["AllReferenceCollection"];
            var owningPropsForClass = propCache["AllOwning"];

            if (owningPropsForClass.Count == 0 && refSeqPropNames.Count == 0 && refColPropNames.Count == 0)
            {
                return;                 // Nothing special to be done for normal properties.
            }
            foreach (var propertyElement in element.Elements().ToArray())
            {
                var isCustomProperty = propertyElement.Name.LocalName == SharedConstants.Custom;
                var propName         = isCustomProperty ? propertyElement.Attribute(SharedConstants.Name).Value : propertyElement.Name.LocalName;
                if (!owningPropsForClass.Contains(propName))
                {
                    if (refSeqPropNames.Contains(propName))
                    {
                        foreach (var refSeqNode in propertyElement.Elements(SharedConstants.Refseq))
                        {
                            refSeqNode.Name = SharedConstants.Objsur;
                        }
                    }
                    else if (refColPropNames.Contains(propName))
                    {
                        foreach (var refColNode in propertyElement.Elements(SharedConstants.Refcol))
                        {
                            refColNode.Name = SharedConstants.Objsur;
                        }
                    }
                    continue;
                }
                if (!propertyElement.HasElements)
                {
                    continue;
                }

                foreach (var ownedElement in propertyElement.Elements().ToArray())
                {
                    if (ownedElement.Name.LocalName == SharedConstants.Objsur)
                    {
                        break;
                    }
                    // Do before the removal call, so we know the parent, and thus, the property name.
                    if (isCustomProperty)
                    {
                        var owningPropertyElement = (element.Elements().Where(customNode => customNode.Name.LocalName == SharedConstants.Custom && customNode.Attribute(SharedConstants.Name) != null && customNode.Attribute(SharedConstants.Name).Value == propertyElement.Attribute(SharedConstants.Name).Value)).First();
                        ownedElement.Remove();
                        FlattenObjectCore(pathname, sortedData, ownedElement, elementGuid);                         // BEFORE we make the objsur!
                        BaseDomainServices.RestoreObjsurElement(owningPropertyElement, ownedElement);
                    }
                    else
                    {
                        var propertyName = ownedElement.Parent.Name.LocalName;
                        ownedElement.Remove();
                        // Move down the nested set of owned objects, and do the same.
                        FlattenOwnedObject(pathname, sortedData, ownedElement, elementGuid, element, propertyName);
                    }
                }
            }
        }