public void GetModelGenErrors_on_EntityDesignArtifact_always_returns_null() { var modelManager = new Mock<ModelManager>(null, null).Object; var modelProvider = new Mock<XmlModelProvider>().Object; using (var artifact = new EntityDesignArtifact(modelManager, new Uri("urn:dummy"), modelProvider)) { Assert.Null(artifact.GetModelGenErrors()); } }
public void GetModelGenErrors_on_EntityDesignArtifact_always_returns_null() { var modelManager = new Mock <ModelManager>(null, null).Object; var modelProvider = new Mock <XmlModelProvider>().Object; using (var artifact = new EntityDesignArtifact(modelManager, new Uri("urn:dummy"), modelProvider)) { Assert.Null(artifact.GetModelGenErrors()); } }
public EnumTypeViewModel(EntityDesignArtifact artifact, string underlyingType) { Initialize(); _underlyingType = String.IsNullOrWhiteSpace(underlyingType) ? ModelConstants.Int32PropertyType : underlyingType; _isFlag = false; _name = String.Empty; _artifact = artifact; _isValid = false; _externalTypeName = String.Empty; _isReferenceExternalType = false; }
internal static void DoMigrate(CommandProcessorContext cpc, EntityDesignArtifact artifact) { var xmlModelProvider = artifact.XmlModelProvider as VSXmlModelProvider; Debug.Assert(xmlModelProvider != null, "Artifact's model provider is not type of VSXmlModelProvider."); if ((xmlModelProvider != null) && (xmlModelProvider.UndoManager != null)) { var undoManager = xmlModelProvider.UndoManager; try { // We need to temporarily disable the Undo Manager because this operation is not undoable. if (undoManager != null) { undoManager.Enable(0); } var command = new MigrateDiagramInformationCommand(artifact); var processor = new CommandProcessor(cpc, shouldNotifyObservers: false); processor.EnqueueCommand(command); processor.Invoke(); Debug.Assert(artifact.DiagramArtifact != null, "Diagram artifact should have been created by now."); if (artifact.DiagramArtifact != null) { // Ensure that diagram file is added to the project. var service = PackageManager.Package.GetService(typeof(DTE)) as DTE; service.ItemOperations.AddExistingItem(artifact.DiagramArtifact.Uri.LocalPath); // Reload the artifacts. artifact.ReloadArtifact(); artifact.IsDirty = true; // The code below ensures mapping window and model-browser window are refreshed. Debug.Assert( PackageManager.Package.DocumentFrameMgr != null, "Could not find the DocumentFrameMgr for this package"); if (PackageManager.Package.DocumentFrameMgr != null) { PackageManager.Package.DocumentFrameMgr.SetCurrentContext(cpc.EditingContext); } } } finally { if (undoManager != null) { undoManager.Enable(1); } } } }
public EnumTypeViewModel(EnumType enumType) { Initialize(); Debug.Assert(enumType != null, "Parameter enum type is null"); if (enumType != null) { _enumType = enumType; _artifact = enumType.Artifact as EntityDesignArtifact; _isFlag = enumType.IsFlags.Value; _name = enumType.Name.Value; _underlyingType = enumType.UnderlyingType.Value; _externalTypeName = enumType.ExternalTypeName.Value; _isReferenceExternalType = (String.IsNullOrWhiteSpace(_externalTypeName) == false); foreach (var member in enumType.Members()) { var vm = new EnumTypeMemberViewModel(this, member); vm.PropertyChanged += enumTypeMember_PropertyChanged; Members.Add(vm); } } _isValid = true; }
internal static void GenerateDatabaseScriptFromModel(EntityDesignArtifact artifact) { VsUtils.EnsureProvider(artifact); var project = VSHelpers.GetProjectForDocument(artifact.Uri.LocalPath, PackageManager.Package); var sp = Services.ServiceProvider; ModelBuilderWizardForm form; ModelBuilderWizardForm.WizardMode startMode; ModelBuilderSettings settings; // Start the hourglass, especially because we'll be incurring a perf hit from validating using (new VsUtils.HourglassHelper()) { // Before running the Generate Database wizard, we have to make sure that the C-Side validates VisualStudioEdmxValidator.LoadAndValidateFiles(artifact.Uri); if ( artifact.ArtifactSet.GetAllErrors() .Count(ei => ei.ErrorClass == ErrorClass.Runtime_CSDL || ei.ErrorClass == ErrorClass.Escher_CSDL) > 0) { VsUtils.ShowErrorDialog(Resources.DatabaseCreation_ValidationFailed); return; } // set up ModelBuilderSettings settings = SetupSettingsAndModeForDbPages( sp, project, artifact, false, ModelBuilderWizardForm.WizardMode.PerformDatabaseConfigAndDBGenSummary, ModelBuilderWizardForm.WizardMode.PerformDBGenSummaryOnly, out startMode); form = new ModelBuilderWizardForm(sp, settings, startMode); } var originalSchemaVersion = settings.TargetSchemaVersion; try { // start the ModelBuilderWizardForm; this will start the workflow in another thread. form.Start(); } catch (Exception e) { VsUtils.ShowErrorDialog( String.Format( CultureInfo.CurrentCulture, Resources.ModelObjectItemWizard_UnexpectedExceptionHasOccurred, e.Message)); return; } // if Wizard was cancelled or the user hit 'X' to close window // no need for any further action if (form.WizardCancelled || !form.WizardFinished) { return; } // If database was configured, add DbContext templates if (startMode == ModelBuilderWizardForm.WizardMode.PerformDatabaseConfigAndDBGenSummary) { var edmxItem = VsUtils.GetProjectItemForDocument(artifact.Uri.LocalPath, sp); new DbContextCodeGenerator().AddDbContextTemplates(edmxItem, settings.UseLegacyProvider); // We need to reload the artifact if we updated the edmx as part of generating // model from the database. if (settings.TargetSchemaVersion != originalSchemaVersion) { artifact.ReloadArtifact(); } } }
// <summary> // Creates commands to remove function imports and complex types corresponding to results if ones exist. // </summary> // <param name="designArtifact">Artifact.</param> // <returns>IEnumerable of commands for deleting function imports and corresponding complex types.</returns> // <remarks> // This function should be called only from RunFinished() method as we don't check whether complex types we // are removing are not used by other function imports or entities. // </remarks> private static IEnumerable<Command> CreateRemoveFunctionImportCommands(EntityDesignArtifact designArtifact) { // we were instructed not to create FunctionImports - but runtime has created them automatically so actually need to delete any which have been created var model = designArtifact.ConceptualModel; var cec = (ConceptualEntityContainer)model.FirstEntityContainer; foreach (var fi in cec.FunctionImports()) { yield return fi.GetDeleteCommand(); if (fi.IsReturnTypeComplexType) { var complexType = model.ComplexTypes().SingleOrDefault( c => ReferenceEquals(c, fi.ReturnTypeAsComplexType.Target)); Debug.Assert( complexType != null, string.Format("Complex type {0} for FunctionImport {1} does not exist", complexType.Name, fi.Name)); if (complexType != null) { yield return complexType.GetDeleteCommand(); } } } }
// internal static to make it more testable internal static CommandProcessor PrepareCommandsAndIntegrityChecks( ModelBuilderSettings modelBuilderSettings, EditingContext editingContext, EntityDesignArtifact designArtifact) { Debug.Assert(modelBuilderSettings != null, "modelBuilderSettings != null"); Debug.Assert(editingContext != null, "editingContext != null"); Debug.Assert(designArtifact != null, "artifact != null"); var commands = new List<Command>(); if (modelBuilderSettings.NewFunctionSchemaProcedures != null && modelBuilderSettings.NewFunctionSchemaProcedures.Count > 0) { // user selected to create new FunctionImports, but don't create the composable ones as these have already been created by the runtime ProgressDialogHelper.ProcessStoredProcedureReturnTypeInformation( designArtifact, modelBuilderSettings.NewFunctionSchemaProcedures, commands, shouldCreateComposableFunctionImports: false); } else { commands.AddRange(CreateRemoveFunctionImportCommands(designArtifact)); } // for SqlServer and SqlServerCe we need to add integrity checks - see the comment below if (commands.Count > 0 || designArtifact.IsSqlFamilyProvider()) { // set up CommandProcessorContext var cpc = new CommandProcessorContext( editingContext, EfiTransactionOriginator.CreateNewModelId, Resources.Tx_CreateFunctionImport); // We propagate facets by default only for Sql Server or Sql Server CE since for other providers facets in C-Space might be intentionally // out of sync with facets from S-Space and we should not break this. For Sql Server and Sql Server CE facets should be in sync in most cases. if (designArtifact.IsSqlFamilyProvider()) { // Add integrity check to enforce synchronizing C-side Property facets to S-side values PropagateStoragePropertyFacetsToConceptualModel.AddRule(cpc, designArtifact); } return new CommandProcessor(cpc, commands); } // no commands or integrity checks to run return null; }
//internal for testing internal static void ReversionModel( IEdmPackage package, EditingContext editingContext, EntityDesignArtifact entityDesignArtifact, Version targetSchemaVersion) { var cpc = new CommandProcessorContext( editingContext, EfiTransactionOriginator.EntityDesignerOriginatorId, EntityDesignerResources.RetargetDocumentFromWatermarkTransactionName, entityDesignArtifact); RetargetXmlNamespaceCommand.RetargetArtifactXmlNamespaces(cpc, entityDesignArtifact, targetSchemaVersion); // The code below ensure that our mapping window works property after the command is executed. Debug.Assert(package.DocumentFrameMgr != null, "Could not find the DocumentFrameMgr for this package"); if (package.DocumentFrameMgr != null) { package.DocumentFrameMgr.SetCurrentContext(editingContext); } }
internal void AddMissingAssociationConnectors(EntityDesignArtifact efArtifact, out bool addedMissingShapes) { addedMissingShapes = false; Debug.Assert(efArtifact != null, "EFArtifact is null"); if (efArtifact != null) { // Now, for all associations, ensure that an association connector is created. var dslDiagram = Diagram as EntityDesignerDiagram; if (efArtifact.ConceptualModel() != null && dslDiagram != null) { var associationsMaterializedAsConnectors = new HashSet<ModelAssociation>(); foreach ( var connector in efArtifact.DesignerInfo.Diagrams.Items.Where(d => d.Id.Value == DiagramId) .SelectMany(d => d.AssociationConnectors)) { // First check if there's a ModelElement for this. var associationConnector = dslDiagram.ModelElement.ModelXRef.GetExisting(connector) as AssociationConnector; if (associationConnector != null && connector.Association.Target != null && !associationsMaterializedAsConnectors.Contains(connector.Association.Target)) { associationsMaterializedAsConnectors.Add(connector.Association.Target); } } var cpc = new CommandProcessorContext( efArtifact.EditingContext, EfiTransactionOriginator.EntityDesignerOriginatorId, "Restore Excluded Elements"); var cp = new CommandProcessor(cpc, shouldNotifyObservers: true); foreach (var association in efArtifact.ConceptualModel().Associations()) { if (!associationsMaterializedAsConnectors.Contains(association)) { var shouldAddConnector = true; var entityTypesOnEnds = association.AssociationEnds().Select(ae => ae.Type.Target); foreach (var entityType in entityTypesOnEnds) { if (entityType != null && entityType.GetAntiDependenciesOfType<Model.Designer.EntityTypeShape>() .Any(ets => ets.Diagram.Id == DiagramId) == false) { shouldAddConnector = false; break; } } if (shouldAddConnector) { var modelDiagram = dslDiagram.ModelElement.ModelXRef.GetExisting(dslDiagram) as ModelDiagram; if (modelDiagram != null) { cp.EnqueueCommand(new CreateAssociationConnectorCommand(modelDiagram, association)); } } } } if (cp.CommandCount > 0) { cp.Invoke(); addedMissingShapes = true; } } } }
internal void AddMissingEntityTypeShapes(EntityDesignArtifact efArtifact, out bool addedMissingShapes) { addedMissingShapes = false; Debug.Assert(efArtifact != null, "EFArtifact is null"); if (efArtifact != null) { // Now, for all entitytypes, ensure that an entitytype shape is created. var dslDiagram = Diagram as EntityDesignerDiagram; if (efArtifact.ConceptualModel() != null && dslDiagram != null) { var entityTypesMaterializedAsShapes = new HashSet<Model.Entity.EntityType>(); foreach ( var designerEntityTypeShape in efArtifact.DesignerInfo.Diagrams.Items.Where(d => d.Id.Value == DiagramId).SelectMany(d => d.EntityTypeShapes)) { // First check if there's a ModelElement for this. var entityTypeShape = dslDiagram.ModelElement.ModelXRef.GetExisting(designerEntityTypeShape) as EntityTypeShape; if (entityTypeShape != null && designerEntityTypeShape.EntityType.Target != null && !entityTypesMaterializedAsShapes.Contains(designerEntityTypeShape.EntityType.Target)) { entityTypesMaterializedAsShapes.Add(designerEntityTypeShape.EntityType.Target); } } var cpc = new CommandProcessorContext( efArtifact.EditingContext, EfiTransactionOriginator.EntityDesignerOriginatorId, "Restore Excluded Elements"); var cp = new CommandProcessor(cpc, shouldNotifyObservers: true); foreach (var entityType in efArtifact.ConceptualModel().EntityTypes()) { if (!entityTypesMaterializedAsShapes.Contains(entityType)) { var modelDiagram = dslDiagram.ModelElement.ModelXRef.GetExisting(dslDiagram) as ModelDiagram; if (modelDiagram != null) { cp.EnqueueCommand(new CreateEntityTypeShapeCommand(modelDiagram, entityType)); } } } if (cp.CommandCount > 0) { cp.Invoke(); addedMissingShapes = true; } } } }
internal static void UpdateModelFromDatabase(EntityDesignArtifact artifact) { VsUtils.EnsureProvider(artifact); var serviceProvider = Services.ServiceProvider; var project = VSHelpers.GetProjectForDocument(artifact.Uri.LocalPath, serviceProvider); // set up ModelBuilderSettings for startMode=PerformDatabaseConfigAndSelectTables ModelBuilderWizardForm.WizardMode startMode; var settings = SetupSettingsAndModeForDbPages( serviceProvider, project, artifact, true, ModelBuilderWizardForm.WizardMode.PerformDatabaseConfigAndSelectTables, ModelBuilderWizardForm.WizardMode.PerformSelectTablesOnly, out startMode); settings.WizardKind = WizardKind.UpdateModel; // use existing storage namespace as new storage namespace if (null != artifact.StorageModel() && null != artifact.StorageModel().Namespace && !string.IsNullOrEmpty(artifact.StorageModel().Namespace.Value)) { settings.StorageNamespace = artifact.StorageModel().Namespace.Value; } // use existing model namespace as new model namespace (this only affects the temporary // artifact but there is a situation where the C-side EntityContainer has been given the // same name as the default model namespace where not setting this causes the temporary // artifact to be unreadable because of symbol clashes) if (null != artifact.ConceptualModel() && null != artifact.ConceptualModel().Namespace && !string.IsNullOrEmpty(artifact.ConceptualModel().Namespace.Value)) { settings.ModelNamespace = artifact.ConceptualModel().Namespace.Value; } settings.ModelBuilderEngine = new UpdateModelFromDatabaseModelBuilderEngine(); // call the ModelBuilderWizardForm var form = new ModelBuilderWizardForm(serviceProvider, settings, startMode); try { form.Start(); } catch (Exception e) { VsUtils.ShowErrorDialog( string.Format( CultureInfo.CurrentCulture, Resources.ModelObjectItemWizard_UnexpectedExceptionHasOccurred, e.Message)); return; } // if Wizard was cancelled or the user hit 'X' to close window // no need for any further action if (form.WizardCancelled || !form.WizardFinished) { return; } // Update the app. or web.config, register build providers etc ConfigFileHelper.UpdateConfig(settings); // use form.ModelBuilderSettings to look at accumulated info and // take appropriate action var editingContext = PackageManager.Package.DocumentFrameMgr.EditingContextManager.GetNewOrExistingContext(artifact.Uri); var shouldReloadArtifact = ProcessAccumulatedInfo(editingContext, artifact, settings); // If database was configured, add DbContext templates if (startMode == ModelBuilderWizardForm.WizardMode.PerformDatabaseConfigAndSelectTables) { var edmxItem = VsUtils.GetProjectItemForDocument(artifact.Uri.LocalPath, serviceProvider); new DbContextCodeGenerator().AddDbContextTemplates(edmxItem, settings.UseLegacyProvider); } // We can reload only after we added EF references to the project otherwise we would get a watermark // saying that the schema version does not match the referenced EF version which would not be true. // If we reload becuase there was an extension that potentially modified the artifact then it does not matter. if (shouldReloadArtifact) { artifact.ReloadArtifact(); artifact.IsDirty = true; } }
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; }
// Intentionally set this to private because we only want this command to be instantiated from static method and not to be combined with other command. private MigrateDiagramInformationCommand(EntityDesignArtifact artifact) { _artifact = artifact; }