/// <inheritdoc /> public override void FixupPartReferences(bool clearMissingReferences = true) { base.FixupPartReferences(clearMissingReferences); var visitor = new AssetCompositePartReferenceCollector(); visitor.VisitAsset(this); var references = visitor.Result; // Reverse the list, so that we can still properly update everything // (i.e. if we have a[0], a[1], a[1].Test, we have to do it from back to front to be valid at each step) // TODO: I don't think this is needed. Find a proper example or remove it. references.Reverse(); foreach (var reference in references) { var realPart = ResolvePartReference(reference.AssetPart); if (realPart != reference.AssetPart) { if (realPart != null || clearMissingReferences) { reference.Path.Apply(this, MemberPathAction.ValueSet, realPart); } } } }
/// <summary> /// Clones a sub-hierarchy of this asset. /// </summary> /// <param name="sourceRootIds">The ids that are the roots of the sub-hierarchies to clone.</param> /// <param name="cleanReference">If true, any reference to a part external to the cloned hierarchy will be set to null.</param> /// <param name="generateNewIdsForIdentifiableObjects">If true, the cloned objects that implement <see cref="IIdentifiable"/> will have new ids.</param> /// <param name="idRemapping">A dictionary containing the remapping of <see cref="IIdentifiable.Id"/> if <see cref="AssetClonerFlags.GenerateNewIdsForIdentifiableObjects"/> has been passed to the cloner.</param> /// <returns>A <see cref="AssetCompositeHierarchyData{TAssetPartDesign, TAssetPart}"/> corresponding to the cloned parts.</returns> /// <remarks>The parts passed to this methods must be independent in the hierarchy.</remarks> public AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart> CloneSubHierarchies(IEnumerable <Guid> sourceRootIds, bool cleanReference, bool generateNewIdsForIdentifiableObjects, bool generateNewBaseInstanceIds, out Dictionary <Guid, Guid> idRemapping) { // Note: Instead of copying the whole asset (with its potentially big hierarchy), // we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. var subTreeHierarchy = new AssetCompositeHierarchyData <TAssetPartDesign, TAssetPart>(); foreach (var rootId in sourceRootIds) { if (!Hierarchy.Parts.ContainsKey(rootId)) { throw new ArgumentException(@"The source root parts must be parts of this asset.", nameof(sourceRootIds)); } subTreeHierarchy.RootPartIds.Add(rootId); subTreeHierarchy.Parts.Add(Hierarchy.Parts[rootId]); foreach (var subTreePart in EnumerateChildParts(Hierarchy.Parts[rootId].Part, true)) { subTreeHierarchy.Parts.Add(Hierarchy.Parts[subTreePart.Id]); } } // clone the parts of the sub-tree var clonedHierarchy = AssetCloner.Clone(subTreeHierarchy, generateNewIdsForIdentifiableObjects ? AssetClonerFlags.GenerateNewIdsForIdentifiableObjects : AssetClonerFlags.None, out idRemapping); // Remap ids from the root id collection to the new ids generated during cloning AssetPartsAnalysis.RemapPartsId(clonedHierarchy, idRemapping); foreach (var rootEntity in clonedHierarchy.RootPartIds) { PostClonePart(clonedHierarchy.Parts[rootEntity].Part); } if (cleanReference) { // set to null reference outside of the sub-tree var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(GetType()); tempAsset.Hierarchy = clonedHierarchy; tempAsset.FixupPartReferences(); } else { // restore initial ids for reference outside of the subtree, so they can be fixed up later. var tempAsset = (AssetCompositeHierarchy <TAssetPartDesign, TAssetPart>)Activator.CreateInstance(GetType()); tempAsset.Hierarchy = clonedHierarchy; var visitor = new AssetCompositePartReferenceCollector(); visitor.VisitAsset(tempAsset); var references = visitor.Result; var revertedIdMapping = idRemapping.ToDictionary(x => x.Value, x => x.Key); foreach (var referencedPart in references.Select(x => x.AssetPart).OfType <IIdentifiable>()) { var realPart = tempAsset.ResolvePartReference(referencedPart); if (realPart == null) { referencedPart.Id = revertedIdMapping[referencedPart.Id]; } } } if (generateNewBaseInstanceIds) { AssetPartsAnalysis.GenerateNewBaseInstanceIds(clonedHierarchy); } return(clonedHierarchy); }