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))); } } } }
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)); }
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); }
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(); } } } }
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); }