Exemple #1
0
        internal static bool Merge(FileInfo inputFile, FileInfo outputFile, DirectoryInfo referenceLoadPath)
        {
            bool singleFileMode = (outputFile == null);

            using (var inputPackage = new DacPackage(inputFile))
            {
                inputPackage.Open(singleFileMode ? FileAccess.ReadWrite : FileAccess.Read);

                var inputModelDoc = inputPackage.Model;
                if (inputModelDoc.Root == null)
                {
                    throw new NullReferenceException("inputModelDoc");
                }

                LogWriter.WriteMessage(String.Format(DacMergeResource.LoadingFile, inputFile.Name));

                // TODO:<GertD> check if this is needed
                // set to last model element in input document
                var inputModelElement = inputModelDoc.Root.Elements().LastOrDefault(e => e.Name.LocalName == Constants.ModelElement);
                if (inputModelElement == null)
                {
                    throw new NullReferenceException(Constants.ModelElement);
                }

                // Event handder to record all the changes to the model
                inputModelElement.Changed += new EventHandler <XObjectChangeEventArgs>
                                                 ((sender, e) =>
                {
                    var element = sender as XElement;
                    if (element != null)
                    {
                        var elementType = Constants.Unknown;
                        var attribute   = element.Attribute(Constants.TypeAttribute);
                        if (attribute != null)
                        {
                            elementType = element.Attribute(Constants.TypeAttribute).Value;
                        }

                        var elementName = Constants.Unnamed;
                        attribute       = element.Attribute(Constants.NameAttribute);
                        if (attribute != null)
                        {
                            elementName = element.Attribute(Constants.NameAttribute).Value;
                        }

                        LogWriter.WriteMessage(
                            String.Format("{0} - {1} - {2}",
                                          e.ObjectChange,
                                          elementType,
                                          elementName));
                    }
                }
                                                 );

                // get child packages, using the CustomData Category="Reference" and Type="SqlSchema"
                //
                // <CustomData Category="Reference" Type="SqlSchema">
                //    <Metadata Value="D:\USERS\GERTD\PROJECTS\DACMERGE\CHILDDB1\BIN\DEBUG\CHILDDB1.DACPAC" Name="FileName"/>
                //    <Metadata Value="ChildDB1.dacpac" Name="LogicalName"/>
                //    <Metadata Value="False" Name="SuppressMissingDependenciesErrors"/>
                //    <Metadata Value="[$(OtherServer)].[$(ChildDB1)]" Name="ExternalParts"/>
                // </CustomData>
                var header = inputModelDoc.Root.Elements()
                             .Where(e => e.Name.LocalName == Constants.HeaderElement);

                var customDataElements = header.Elements()
                                         .Where(e => e.Name.LocalName == Constants.CustomData)
                                         .Where(a => a.Attribute(Constants.CategoryAttribute).Value == Constants.Reference)
                                         .Where(a => a.Attribute(Constants.TypeAttribute).Value == Constants.SqlSchema);

                Int32 maxDisambiguator = 0;
                var   x = inputModelElement.Descendants()
                          .Where(e => e.Name.LocalName == Constants.AnnotationElement)
                          .Where(a =>
                {
                    var attribute = a.Attribute(Constants.DisambiguatorAttribute);
                    return(attribute != null);
                })
                          .LastOrDefault().Attribute(Constants.DisambiguatorAttribute).Value;

                Int32.TryParse((String.IsNullOrEmpty(x) ? "3" : x), out maxDisambiguator);

                Int32 maxCummulativeDisambiguator = maxDisambiguator;

                foreach (var customDataElement in customDataElements.ToList())
                {
                    var inSameDb = String.IsNullOrEmpty(customDataElement.Elements()
                                                        .Where(e => e.Name.LocalName == Constants.Metadata)
                                                        .Where(a => a.Attribute(Constants.NameAttribute).Value == Constants.ExternalParts)
                                                        .Select(a => a.Attribute(Constants.ValueAttribute).Value).FirstOrDefault());

                    if (inSameDb)
                    {
                        // get dacpac filename
                        var childDacPac = customDataElement.Elements()
                                          .Where(e => e.Name.LocalName == Constants.Metadata)
                                          .Where(a => a.Attribute(Constants.NameAttribute).Value == Constants.FileName)
                                          .Select(a => a.Attribute(Constants.ValueAttribute).Value).FirstOrDefault();

                        if (childDacPac == null || String.IsNullOrEmpty(childDacPac))
                        {
                            throw new ArgumentNullException("childDacPac");
                        }

                        var childFile = ResolveFileName(childDacPac, inputFile, referenceLoadPath);
                        if (childFile == null)
                        {
                            throw new ArgumentNullException("childFile");
                        }

                        if (!childFile.Exists)
                        {
                            throw new FileNotFoundException(childDacPac);
                        }

                        LogWriter.WriteMessage(String.Format(DacMergeResource.MergeFile, childFile.Name));

                        // import child package
                        using (var childPackage = new DacPackage(childFile))
                        {
                            childPackage.Open(FileAccess.Read);

                            // var childModelPart = childPackage.GetPart(modelPartUri);

                            var childModelDoc = childPackage.Model; // XDocument.Load(XmlReader.Create(childModelPart.GetStream()));
                            if (childModelDoc.Root == null)
                            {
                                throw new NullReferenceException("childModelDoc");
                            }

                            var childModelElement = childModelDoc.Root.Elements().FirstOrDefault(e => e.Name.LocalName == Constants.ModelElement);
                            if (childModelElement == null)
                            {
                                throw new NullReferenceException(Constants.ModelElement);
                            }

                            // remove DatabaseOptions from child model
                            RemoveElements(childModelElement, Constants.TypeAttribute, SqlElementType.SqlDatabaseOptions);

                            // update Disambiguator for Annotations
                            var annotations = childModelElement.Descendants()
                                              .Where(e => e.Name.LocalName == Constants.AnnotationElement)
                                              .Where(a =>
                            {
                                var attribute = a.Attribute(Constants.DisambiguatorAttribute);
                                return(attribute != null);
                            });

                            foreach (var annotation in annotations)
                            {
                                Int32 disambiguator = 0;

                                if (Int32.TryParse(annotation.Attribute(Constants.DisambiguatorAttribute).Value, out disambiguator))
                                {
                                    Int32 newdisambiguator = disambiguator + maxDisambiguator;
                                    annotation.Attribute(Constants.DisambiguatorAttribute).Value = newdisambiguator.ToString(CultureInfo.InvariantCulture);
                                    maxCummulativeDisambiguator = Math.Max(newdisambiguator, maxCummulativeDisambiguator);
                                }
                                else
                                {
                                    System.Diagnostics.Debug.Assert(false);
                                }
                            }

                            // update Disambiguator for AttachedAnnotations
                            var attachedAnnotations = childModelElement.Descendants()
                                                      .Where(e => e.Name.LocalName == Constants.AttachedAnnotationElement)
                                                      .Where(a =>
                            {
                                var attribute = a.Attribute(Constants.DisambiguatorAttribute);
                                return(attribute != null);
                            });

                            foreach (var attachedAnnotation in attachedAnnotations)
                            {
                                Int32 disambiguator = 0;
                                if (Int32.TryParse(attachedAnnotation.Attribute(Constants.DisambiguatorAttribute).Value, out disambiguator))
                                {
                                    Int32 newdisambiguator = disambiguator + maxDisambiguator;
                                    attachedAnnotation.Attribute(Constants.DisambiguatorAttribute).Value = newdisambiguator.ToString(CultureInfo.InvariantCulture);
                                }
                                else
                                {
                                    System.Diagnostics.Debug.Assert(false);
                                }
                            }

                            var childElements = childModelElement.Elements();

                            LogWriter.WriteMessage(String.Format(DacMergeResource.MergeModelElements, childElements.Count()));

                            inputModelElement.Add(childElements);

                            maxDisambiguator = maxCummulativeDisambiguator;

                            customDataElement.Remove();
                        }
                    }
                }

                DacPackage outputPackage = null;
                if (singleFileMode)
                {
                    outputPackage = inputPackage;
                }
                else
                {
                    outputPackage = new DacPackage(outputFile);
                    outputPackage.Open(FileAccess.ReadWrite);
                }

                if (singleFileMode)
                {
                    LogWriter.WriteMessage(String.Format(DacMergeResource.Stream, DacPackage.ModelUri));
                    inputModelDoc.Save(outputPackage.GetStream(DacPackage.ModelUri));
                }
                else
                {
                    LogWriter.WriteMessage(DacMergeResource.CopyingStreams);

                    // copy all parts from input to output package,
                    // except for the model.xml stream which will is replace with the merged XML document content
                    foreach (var part in inputPackage.GetParts())
                    {
                        LogWriter.WriteMessage(String.Format(DacMergeResource.Stream, part.Uri));

                        var outputPart = outputPackage.CreatePartAs(part);

                        if (part.Uri == DacPackage.ModelUri)
                        {
                            inputModelDoc.Save(outputPart.GetStream());
                        }
                        else
                        {
                            if (outputPart == null)
                            {
                                throw new NullReferenceException("outputPart");
                            }

                            part.GetStream().CopyTo(outputPart.GetStream());
                        }
                    }
                }

                var outputOriginDoc = XDocument.Load(XmlReader.Create(outputPackage.GetStream(DacPackage.OriginUri)));
                if (outputOriginDoc.Root == null)
                {
                    throw new NullReferenceException("outputOriginDoc");
                }

                LogWriter.WriteMessage(DacMergeResource.CalculatingChecksum);
                var newChecksum = outputPackage.CalculateChecksum();
                LogWriter.WriteMessage(DacPackage.ByteArrayToString(newChecksum));

                LogWriter.WriteMessage(DacMergeResource.UpdatingChecksum);
                outputPackage.UpdateChecksum(newChecksum);

                outputOriginDoc.Save(outputPackage.GetStream(DacPackage.OriginUri));

                outputPackage.Close();
                inputPackage.Close();
            }

            return(true);
        }