예제 #1
0
        internal static HashSet <string> GetVSArtifactFileExtensions()
        {
            if (_artifactFileExtensions == null)
            {
                _artifactFileExtensions =
                    new HashSet <string>(StringComparer.OrdinalIgnoreCase)
                {
                    ExtensionEdmx, ExtensionDiagram
                };

                // add any other extensions registered by converters
                foreach (var exportInfo in EscherExtensionPointManager.LoadModelConversionExtensions())
                {
                    var fileExtension = exportInfo.Metadata.FileExtension;

                    // ensure that the extension starts with a '.'
                    if (fileExtension.StartsWith(".", StringComparison.Ordinal) == false)
                    {
                        fileExtension = "." + fileExtension;
                    }

                    // add it if it isn't already in the list (duplicates will be checked for during load/save)
                    if (_artifactFileExtensions.Contains(fileExtension) == false)
                    {
                        _artifactFileExtensions.Add(fileExtension);
                    }
                }
            }
            return(_artifactFileExtensions);
        }
        private void DispatchInternal()
        {
            Debug.Assert(
                WizardKind == WizardKind.UpdateModel || WizardKind == WizardKind.Generate, "Unexpected value for WizardKind = " + WizardKind);

            var modelGenerationExtensions = EscherExtensionPointManager.LoadModelGenerationExtensions();

            if (modelGenerationExtensions.Length > 0) // don't create context if not needed
            {
                var modelGenerationExtensionContext = CreateContext();

                foreach (var exportInfo in modelGenerationExtensions)
                {
                    var extension = exportInfo.Value;
                    try
                    {
                        DispatchToSingleExtension(extension, modelGenerationExtensionContext);
                    }
                    catch (Exception e)
                    {
                        VsUtils.ShowErrorDialog(
                            string.Format(
                                CultureInfo.CurrentCulture,
                                Resources.Extensibility_ErrorOccurredDuringCallToExtension,
                                extension.GetType().FullName,
                                VsUtils.ConstructInnerExceptionErrorMessage(e)));
                    }
                }
            }
        }
예제 #3
0
        internal static bool TryGetBufferViaExtensions(
            ProjectItem projectItem, string fileContents,
            out string documentViaExtensions, out List <ExtensionError> errors)
        {
            var converters  = EscherExtensionPointManager.LoadModelConversionExtensions();
            var serializers = EscherExtensionPointManager.LoadModelTransformExtensions();

            if (projectItem == null ||
                !VsUtils.EntityFrameworkSupportedInProject(projectItem.ContainingProject, PackageManager.Package, allowMiscProject: false) ||
                (serializers.Length == 0 && converters.Length == 0))
            {
                errors = new List <ExtensionError>();
                documentViaExtensions = "";
                return(false);
            }

            return(TryGetBufferViaExtensions(
                       PackageManager.Package, projectItem, fileContents,
                       converters, serializers, out documentViaExtensions, out errors));
        }
예제 #4
0
        private string DispatchSaveToExtensions(string fileContents)
        {
            Debug.Assert(fileContents != null, "fileContents != null");

            // see if any extensions want to participate in saving
            if (Hierarchy != null)
            {
                var serializers = EscherExtensionPointManager.LoadModelTransformExtensions();
                var converters  = EscherExtensionPointManager.LoadModelConversionExtensions();

                var projectItem = VsUtils.GetProjectItem(Hierarchy, ItemId);

                if ((serializers.Length > 0 || converters.Length > 0) &&
                    projectItem != null &&
                    VsUtils.EntityFrameworkSupportedInProject(
                        projectItem.ContainingProject, PackageManager.Package, allowMiscProject: false))
                {
                    return(DispatchSaveToExtensions(PackageManager.Package, projectItem, fileContents, converters, serializers));
                }
            }

            return(fileContents);
        }
예제 #5
0
        private static bool ProcessAccumulatedInfo(
            EditingContext editingContext, EntityDesignArtifact existingArtifact, ModelBuilderSettings settings)
        {
            var schemaVersionChanged = existingArtifact.SchemaVersion != settings.TargetSchemaVersion;

            EntityDesignModelManager tempModelManager = null;
            FileInfo tempEdmxFile    = null;
            Uri      tempEdmxFileUri = null;

            try
            {
                // set up new temporary ModelManager
                // NOTE:  use an EFArtifact with VSArtifactSet.  This is so we get the in-vs behavior of artifact sets,
                // but don't rely on VS loading the model into the RDT, etc..
                tempModelManager = new EntityDesignModelManager(new EFArtifactFactory(), new VSArtifactSetFactory());

                tempEdmxFile    = ConstructTempEdmxFile(settings);
                tempEdmxFileUri = new Uri(tempEdmxFile.FullName, UriKind.Absolute);
                var tempArtifactBasedOnDatabase = tempModelManager.GetNewOrExistingArtifact(tempEdmxFileUri, new VanillaXmlModelProvider());

                // if a model generation extension has changed the model, ensure that it is
                // valid before we start to process it
                if (settings.HasExtensionChangedModel)
                {
                    ValidateArtifact(tempModelManager, tempArtifactBasedOnDatabase, WizardKind.Generate);
                }

                // Note: later we want the diagram shapes and connectors to be created in the current active diagram
                // so set TransactionContext appropriately.
                EfiTransactionContext transactionContext = null;
                var contextItem = editingContext.Items.GetValue <DiagramManagerContextItem>();
                if (contextItem != null &&
                    contextItem.DiagramManager != null)
                {
                    var activeDiagram = contextItem.DiagramManager.ActiveDiagram;
                    if (activeDiagram != null)
                    {
                        transactionContext = new EfiTransactionContext();
                        transactionContext.Add(
                            EfiTransactionOriginator.TransactionOriginatorDiagramId, new DiagramContextItem(activeDiagram.DiagramId));
                    }
                }

                // clear search if active (Note: in Model.Tests it is OK for below to be null)
                var explorerInfo = editingContext.Items.GetValue <ExplorerWindow.ExplorerInfo>();
                if (explorerInfo != null)
                {
                    var explorerFrame = explorerInfo._explorerFrame;
                    if (explorerFrame != null)
                    {
                        if (explorerFrame.SearchIsActive)
                        {
                            explorerFrame.ResetSearchCommand.Execute(null);
                        }
                    }
                }

                var cpc = new CommandProcessorContext(
                    editingContext, EfiTransactionOriginator.UpdateModelFromDatabaseId,
                    Resources.Tx_UpdateModelFromDatabase, null, transactionContext);

                if (schemaVersionChanged)
                {
                    // changing namespaces must be done in a separate transaction otherwise XmlEditor
                    // will not pick-up changes made to xml after namespaces are changed
                    CommandProcessor.InvokeSingleCommand(
                        cpc,
                        new RetargetXmlNamespaceCommand(existingArtifact, settings.TargetSchemaVersion));
                }

                // Update the existing artifact based on tempArtifactBasedOnDatabase
                var commands = new List <Command>();
                var cmd      = new UpdateModelFromDatabaseCommand(tempArtifactBasedOnDatabase);
                commands.Add(cmd);

                // set up our post event to clear out the error list
                cmd.PostInvokeEvent +=
                    (o, e) =>
                {
                    var errorList =
                        ErrorListHelper.GetSingleDocErrorList(e.CommandProcessorContext.Artifact.Uri);
                    if (errorList != null)
                    {
                        errorList.Clear();
                    }
                };

                DesignerInfo designerInfo;
                if (existingArtifact.DesignerInfo().TryGetDesignerInfo(OptionsDesignerInfo.ElementName, out designerInfo))
                {
                    var optionsDesignerInfo = designerInfo as OptionsDesignerInfo;
                    Debug.Assert(optionsDesignerInfo != null, "expected non-null optionsDesignerInfo");
                    if (optionsDesignerInfo != null)
                    {
                        // pluralization checkbox
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.CheckPluralizationInWizard,
                            OptionsDesignerInfo.AttributeEnablePluralization,
                            settings.UsePluralizationService, optionsDesignerInfo, commands);

                        // include FKs in model checkbox
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.CheckIncludeForeignKeysInModel,
                            OptionsDesignerInfo.AttributeIncludeForeignKeysInModel,
                            settings.IncludeForeignKeysInModel, optionsDesignerInfo, commands);

                        // ensure UseLegacyProvider is set
                        AddUpdateDesignerPropertyCommand(
                            optionsDesignerInfo.UseLegacyProvider,
                            OptionsDesignerInfo.AttributeUseLegacyProvider,
                            settings.UseLegacyProvider, optionsDesignerInfo, commands);
                    }
                }

                // create a new FunctionImport for every new Function created (whether composable or not)
                // (or delete Functions if ProgressDialog did not finish successfully)
                // Note: this must take place as a DelegateCommand as ProcessStoredProcedureReturnTypeInformation()
                // can depend on finding the existing Functions to delete. And it won't find them until the
                // ReplaceSsdlCommand within UpdateModelFromDatabaseCommand has executed.
                var createMatchingFunctionImportsDelegateCommand = new DelegateCommand(
                    () =>
                {
                    var functionImportCommands = new List <Command>();
                    ProgressDialogHelper.ProcessStoredProcedureReturnTypeInformation(
                        existingArtifact, settings.NewFunctionSchemaProcedures, functionImportCommands, true);

                    if (functionImportCommands.Count > 0)
                    {
                        new CommandProcessor(cpc, functionImportCommands)
                        .Invoke();
                    }
                });
                commands.Add(createMatchingFunctionImportsDelegateCommand);

                // if needed, create a command to dispatch any extensions
                if (EscherExtensionPointManager.LoadModelGenerationExtensions().Length > 0)
                {
                    var dispatchCommand = new DispatchToExtensionsCommand(settings);
                    commands.Add(dispatchCommand);
                }

                // do all the work here in one transaction
                new CommandProcessor(cpc, commands)
                .Invoke();

                // if an extension has changed the model, do a full reload
                if (schemaVersionChanged || settings.HasExtensionChangedModel)
                {
                    return(true);
                }
                else
                {
                    // reset the is-designer safe flag - this can be set incorrectly when the document is reloaded after ssdl has been updated,
                    // but csdl & msl haven't.  Here, the model is correct, but we need to get views to refresh themselves after we
                    // reset the is-designer-safe flag.
                    // Perf note: reloading the artifact can take some time - so only reload if IsDesignerSafe has changed
                    var isDesignerSafeBefore = existingArtifact.IsDesignerSafe;
                    existingArtifact.DetermineIfArtifactIsDesignerSafe();
                    var isDesignerSafeAfter = existingArtifact.IsDesignerSafe;
                    if (isDesignerSafeAfter != isDesignerSafeBefore)
                    {
                        existingArtifact.FireArtifactReloadedEvent();
                    }
                }
            }
            finally
            {
                // remove tempArtifactBasedOnDatabase to dispose EFObject's properly
                if (tempEdmxFileUri != null &&
                    tempModelManager != null)
                {
                    tempModelManager.ClearArtifact(tempEdmxFileUri);
                }

                // dispose of our temp model manager
                if (tempModelManager != null)
                {
                    tempModelManager.Dispose();
                }

                // delete temporary file
                if (tempEdmxFile != null &&
                    tempEdmxFile.Exists)
                {
                    try
                    {
                        tempEdmxFile.Delete();
                    }
                    catch (IOException)
                    {
                        // do nothing if delete fails
                    }
                }
            }

            return(false);
        }
        public void RunFinished()
        {
            if (_edmxItem == null)
            {
                if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.EmptyModelCodeFirst ||
                    _modelBuilderSettings.GenerationOption == ModelGenerationOption.CodeFirstFromDatabase)
                {
                    Debug.Assert(
                        _modelBuilderSettings.ModelBuilderEngine == null ^
                        _modelBuilderSettings.GenerationOption == ModelGenerationOption.CodeFirstFromDatabase,
                        "Model should be null for Empty Model and not null CodeFirst from database");

                    AddCodeFirstItems();
                }

                return;
            }

            var fileExtension = Path.GetExtension(_edmxItem.FileNames[1]);

            Debug.Assert(
                _modelBuilderSettings.Project.Equals(_edmxItem.ContainingProject),
                "ActiveSolutionProject is not the EDMX file's containing project");
            using (new VsUtils.HourglassHelper())
            {
                var    package = PackageManager.Package;
                Window window  = null;

                try
                {
                    ConfigFileHelper.UpdateConfig(_modelBuilderSettings);

                    // save the model generated in the wizard UI.
                    if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase)
                    {
                        var writingModelWatch = new Stopwatch();
                        writingModelWatch.Start();
                        var modelEdmx = ((EdmxModelBuilderEngine)_modelBuilderSettings.ModelBuilderEngine).Edmx;

                        if (!string.Equals(fileExtension, EntityDesignArtifact.ExtensionEdmx, StringComparison.OrdinalIgnoreCase))
                        {
                            // convert the file if this isn't EDMX
                            var edmxFileInfo      = new FileInfo(_edmxItem.FileNames[1]);
                            var conversionContext = new ModelConversionContextImpl(
                                _edmxItem.ContainingProject,
                                _edmxItem,
                                edmxFileInfo,
                                _modelBuilderSettings.TargetSchemaVersion,
                                modelEdmx);
                            VSArtifact.DispatchToConversionExtensions(
                                EscherExtensionPointManager.LoadModelConversionExtensions(),
                                fileExtension,
                                conversionContext,
                                loading: false);
                            File.WriteAllText(edmxFileInfo.FullName, conversionContext.OriginalDocument);
                        }
                        else
                        {
                            // we need to use XmlWriter to output so that XmlDeclaration is preserved.
                            using (var modelWriter = XmlWriter.Create(
                                       _edmxItem.FileNames[1],
                                       new XmlWriterSettings {
                                Indent = true
                            }))
                            {
                                modelEdmx.WriteTo(modelWriter);
                            }
                        }

                        writingModelWatch.Stop();
                        VsUtils.LogOutputWindowPaneMessage(
                            _edmxItem.ContainingProject,
                            string.Format(
                                CultureInfo.CurrentCulture,
                                Properties.Resources.WritingModelTimeMsg,
                                writingModelWatch.Elapsed));
                    }

                    // set the ItemType for the generated .edmx file
                    if (_modelBuilderSettings.VSApplicationType != VisualStudioProjectSystem.Website &&
                        string.Equals(
                            fileExtension,
                            EntityDesignArtifact.ExtensionEdmx,
                            StringComparison.OrdinalIgnoreCase))
                    {
                        _edmxItem.Properties.Item(ItemTypePropertyName).Value = EntityDeployBuildActionName;
                    }

                    // now open created file in VS using default viewer
                    window = _edmxItem.Open(Constants.vsViewKindPrimary);
                    Debug.Assert(window != null, "Unable to get window for created edmx file");
                }
                finally
                {
                    package.ModelGenErrorCache.RemoveErrors(_edmxItem.FileNames[1]);
                }

                // Construct an editing context and make all final edits that require the file is opened.
                var edmxFileUri    = new Uri(_edmxItem.FileNames[1]);
                var designArtifact =
                    package.ModelManager.GetNewOrExistingArtifact(
                        edmxFileUri, new VSXmlModelProvider(package, package)) as EntityDesignArtifact;
                Debug.Assert(
                    designArtifact != null,
                    "artifact should be of type EntityDesignArtifact but received type " + designArtifact.GetType().FullName);
                Debug.Assert(
                    designArtifact.StorageModel != null, "designArtifact StorageModel cannot be null for Uri " + edmxFileUri.AbsolutePath);
                Debug.Assert(
                    designArtifact.ConceptualModel != null,
                    "designArtifact ConceptualModel cannot be null for Uri " + edmxFileUri.AbsolutePath);

                if (designArtifact != null &&
                    designArtifact.StorageModel != null &&
                    designArtifact.ConceptualModel != null)
                {
                    var designerSafeBeforeAddingTemplates = designArtifact.IsDesignerSafe;

                    var editingContext =
                        package.DocumentFrameMgr.EditingContextManager.GetNewOrExistingContext(designArtifact.Uri);
                    Debug.Assert(editingContext != null, "Null EditingContext for artifact " + edmxFileUri.AbsolutePath);
                    if (editingContext != null)
                    {
                        // Add DbContext templates when generation is GenerateFromDatabase. (connection is configured)
                        if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase)
                        {
                            new DbContextCodeGenerator().AddDbContextTemplates(
                                _edmxItem,
                                _modelBuilderSettings.UseLegacyProvider);
                        }

                        // Create FunctionImports for every new Function
                        var cp = PrepareCommandsAndIntegrityChecks(_modelBuilderSettings, editingContext, designArtifact);

                        if (DbContextCodeGenerator.TemplateSupported(_edmxItem.ContainingProject, package))
                        {
                            // Add command setting CodeGenerationStrategy to "None" for EmptyModel. (connection is not yet configured)
                            // NOTE: For EmptyModel, the templates will be added after the connection is configured.
                            //       (i.e. during "Generate Database from Model" or "Refresh from Database")
                            if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.EmptyModel)
                            {
                                var cmd = EdmUtils.SetCodeGenStrategyToNoneCommand(designArtifact);
                                if (cmd != null)
                                {
                                    if (cp == null)
                                    {
                                        var cpc = new CommandProcessorContext(
                                            editingContext,
                                            EfiTransactionOriginator.CreateNewModelId,
                                            Resources.Tx_SetCodeGenerationStrategy);
                                        cp = new CommandProcessor(cpc, cmd);
                                    }
                                    else
                                    {
                                        cp.EnqueueCommand(cmd);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Templates not supported, add reference to SDE. (.NET Framework 3.5)
                            VsUtils.AddProjectReference(_edmxItem.ContainingProject, "System.Data.Entity");
                        }

                        if (cp != null)
                        {
                            cp.Invoke();
                        }

                        // save the artifact to make it look as though updates were part of creation
                        _edmxItem.Save();

                        if (_modelBuilderSettings.GenerationOption == ModelGenerationOption.GenerateFromDatabase &&
                            !designerSafeBeforeAddingTemplates)
                        {
                            // If the artifact became safe after adding references we need to reload it (this can happen
                            // on .NET Framework 4 where we would originally create a v3 edmx if the user selected EF6 -
                            // the artifact will be flagged as invalid since there is no runtime which could handle v3
                            // but after we added references to EF6 the artifacts becomes valid and need to be reloaded).
                            designArtifact.DetermineIfArtifactIsDesignerSafe();
                            if (designArtifact.IsDesignerSafe)
                            {
                                Debug.Assert(!designArtifact.IsDirty, "Reloading dirty artifact - changes will be lost.");

                                // Since the artifact was originally not valid we did not create the diagram for it.
                                // Using ReloadDocData will cause the diagram to be recreated. Note we don't need to
                                // reload the artifact itself since it has not changed.
                                ((DocData)
                                 VSHelpers.GetDocData(package, designArtifact.Uri.LocalPath)).ReloadDocData(0);
                            }
                        }
                    }

                    if (window != null)
                    {
                        window.Activate();
                    }
                }
            }
        }
예제 #7
0
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var baseProperties = base.GetProperties(attributes);

            // clear out dictionary, as we will rebuild it in this method
            _propertyDescriptorToOwner.Clear();

            if (RunningInVS)
            {
                // we only dispatch to extensions when we are running in VS.  This is because there is a dep on vS things like ProjectItem
                var el = WrappedItem as EFElement;
                Debug.Assert(el != null, "wrapped item is null");
                if (el != null)
                {
                    var currentSelectionOrNull = EscherExtensionPointManager.DetermineEntityDesignerSelection(el);

                    if (currentSelectionOrNull != null)
                    {
                        var currentSelection = (EntityDesignerSelection)currentSelectionOrNull;
                        Debug.Assert((int)currentSelection != 0, "unexpected value for current selection");
                        var extensions = EscherExtensionPointManager.LoadPropertyDescriptorExtensions();
                        if (extensions.Length > 0)
                        {
                            // Note that if the user adds an EDMX file to their project and chooses not to save the project file,
                            // the project item below can be null; it won't even exist in the miscellaneous files project.
                            var projectItem = VsUtils.GetProjectItemForDocument(el.Artifact.Uri.LocalPath, PackageManager.Package);
                            if (projectItem != null &&
                                VsUtils.EntityFrameworkSupportedInProject(
                                    projectItem.ContainingProject, PackageManager.Package, allowMiscProject: false))
                            {
                                var targetSchemaVersion =
                                    EdmUtils.GetEntityFrameworkVersion(projectItem.ContainingProject, PackageManager.Package);

                                //  Use MEF extensions to create "owner" objects that define new property descriptors to add into the property sheet.
                                //  TODO: We track 'visited factories' since have to load the App-DB contracts as well as the standard contracts, but
                                //        MEF also loads the standard contracts in addition to the App-DB contracts. Need to see if MEF can support
                                //        otherwise.
                                var propDescriptorOwners = new List <Object>();
                                var visitedFactories     = new HashSet <IEntityDesignerExtendedProperty>();
                                foreach (var ex in extensions)
                                {
                                    if (((int)ex.Metadata.EntityDesignerSelection & (int)currentSelection) == (int)currentSelection)
                                    {
                                        // Continue processing this extension
                                        var factory = ex.Value;
                                        if (factory != null &&
                                            !visitedFactories.Contains(factory))
                                        {
                                            visitedFactories.Add(factory);
                                            try
                                            {
                                                var extensionContext = new PropertyExtensionContextImpl(
                                                    EditingContext, projectItem, targetSchemaVersion,
                                                    factory.GetType().Assembly.GetName().GetPublicKeyToken());

                                                var xelem = el.XElement;
                                                var sem   = el as StorageEntityModel;
                                                if (currentSelection == EntityDesignerSelection.StorageModelEntityContainer &&
                                                    sem != null)
                                                {
                                                    xelem = sem.FirstEntityContainer.XElement;
                                                }

                                                var o = factory.CreateProperty(xelem, extensionContext);
                                                if (o != null)
                                                {
                                                    propDescriptorOwners.Add(o);
                                                }
                                            }
                                            catch (Exception e)
                                            {
                                                var exceptionMessage = VsUtils.ConstructInnerExceptionErrorMessage(e);
                                                var errorMessage     = String.Format(
                                                    CultureInfo.CurrentCulture, Resources.Extensibility_ErrorOccurredDuringCallToExtension,
                                                    factory.GetType().FullName, exceptionMessage);
                                                VsUtils.ShowErrorDialog(errorMessage);
                                            }
                                        }
                                    }
                                }

                                //
                                //  Create PropertyDescriptors over the new "owner"
                                //
                                foreach (var o in propDescriptorOwners)
                                {
                                    var props = TypeDescriptor.GetProperties(o, attributes, false);
                                    foreach (PropertyDescriptor pd in props)
                                    {
                                        var reflectedPropertyDescriptor = new ReflectedPropertyDescriptor(EditingContext, pd, o);
                                        if (reflectedPropertyDescriptor.IsBrowsable)
                                        {
                                            if (_propertyDescriptorToOwner.ContainsKey(reflectedPropertyDescriptor))
                                            {
                                                // handle degenerate error case where dictionary already contains key.  This shouldn't happen, but this is here just to be safe.
                                                Debug.Fail("_propertyDescriptor2Owner table already contains entry");
                                                _propertyDescriptorToOwner.Remove(reflectedPropertyDescriptor);
                                            }
                                            _propertyDescriptorToOwner.Add(reflectedPropertyDescriptor, o);
                                            baseProperties.Add(reflectedPropertyDescriptor);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(baseProperties);
        }