/// <summary> /// Update the underlying function/store-procedure if they are changed. /// </summary> private void UpdateFunctionImportFunction(CommandProcessorContext cpc) { if (Function != FunctionImport.Function) { // if the user selected "(None)" then delete the FunctionImportMapping if (Function == null) { DeleteEFElementCommand.DeleteInTransaction(cpc, FunctionImport.FunctionImportMapping); } // if the user selected another stored procedure, update the mapping // and the parameters of the function import else { var functionImportMapping = FunctionImport.FunctionImportMapping; if (functionImportMapping == null) { // if there isn't a FunctionImportMapping already, we need to create it with the FunctionName if (FunctionImport.Artifact != null && FunctionImport.Artifact.MappingModel() != null && FunctionImport.Artifact.MappingModel().FirstEntityContainerMapping != null) { var cmdFuncImpMapping = new CreateFunctionImportMappingCommand( FunctionImport.Artifact.MappingModel().FirstEntityContainerMapping, Function, FunctionImport); CommandProcessor.InvokeSingleCommand(cpc, cmdFuncImpMapping); } } else { // update the FunctionName in the FunctionImportMapping functionImportMapping.FunctionName.SetRefName(Function); AddToBeNormalizedEFContainerItem(functionImportMapping); } } // finally, update the parameters of the function import to match the function CreateFunctionImportCommand.UpdateFunctionImportParameters(cpc, FunctionImport, Function); } }
protected override void InvokeInternal(CommandProcessorContext cpc) { var service = cpc.EditingContext.GetEFArtifactService(); var artifact = service.Artifact; Debug.Assert(artifact != null, "Null Artifact"); if (null == artifact) { return; } // construct a mapping of the existing model's C-side objects // and their S-side identities before anything is updated var existingModel = new ExistingModelSummary(artifact); // replace the old SSDL with the new and fixup any references // in the MSL that broke because of the replacement of the SSDL // (i.e. the S-side Alias and S-side EntityContainer name) var replaceSsdlCommand = new ReplaceSsdlCommand(_newArtifactFromDB.StorageModel()); CommandProcessor.InvokeSingleCommand(cpc, replaceSsdlCommand); // remove any mappings with references which no longer work // with the new SSDL var deleteUnboundMappingsCommand = new DeleteUnboundMappingsCommand(); CommandProcessor.InvokeSingleCommand(cpc, deleteUnboundMappingsCommand); // remove any mappings which should no longer be mapped with the new SSDL // but actually are because a new S-side object with identical name // but different identity has been added var deleteChangedIdentityMappingsCommand = new DeleteChangedIdentityMappingsCommand(existingModel); CommandProcessor.InvokeSingleCommand(cpc, deleteChangedIdentityMappingsCommand); // from the temp model for the updated database determine which // C-side objects need to be added/updated and then update the // C- and M- side models appropriately var modelFromUpdatedDatabase = new UpdatedModelSummary(_newArtifactFromDB); var updateCsdlAndMslCommand = new UpdateConceptualAndMappingModelsCommand(existingModel, modelFromUpdatedDatabase); CommandProcessor.InvokeSingleCommand(cpc, updateCsdlAndMslCommand); // fix up Function Import parameters and add integrity checks if (artifact.MappingModel() != null && artifact.MappingModel().FirstEntityContainerMapping != null) { // Function Import parameters are now out-of-date compared to the updated Function ones. // We need to update them as otherwise there is no way to do so using Escher. foreach (var fim in artifact.MappingModel().FirstEntityContainerMapping.FunctionImportMappings()) { if (null != fim.FunctionImportName && null != fim.FunctionImportName.Target && null != fim.FunctionName && null != fim.FunctionName.Target) { CreateFunctionImportCommand.UpdateFunctionImportParameters( cpc, fim.FunctionImportName.Target, fim.FunctionName.Target); } } // Add integrity checks to enforce mapping rules foreach (var esm in artifact.MappingModel().FirstEntityContainerMapping.EntitySetMappings()) { EnforceEntitySetMappingRules.AddRule(cpc, esm); } // add the integrity check to propagate all appropriate StoreGeneratedPattern values to the S-side // Note: should not propagate "None"/defaulted values to prevent those C-side values overwriting // correctly updated S-side StoreGeneratedPattern values which were just received from the runtime PropagateStoreGeneratedPatternToStorageModel.AddRule(cpc, artifact, false); // Add integrity check to enforce synchronizing C-side Property facets to S-side values var shouldSynchronizePropertyFacets = ModelHelper.GetDesignerPropertyValueFromArtifactAsBool( OptionsDesignerInfo.ElementName, OptionsDesignerInfo.AttributeSynchronizePropertyFacets, OptionsDesignerInfo.SynchronizePropertyFacetsDefault(artifact), artifact); if (shouldSynchronizePropertyFacets) { PropagateStoragePropertyFacetsToConceptualModel.AddRule(cpc, artifact); } } }
public void Simple_FunctionImport() { UITestRunner.Execute(TestContext.TestName, () => { const string typePrefix = "Simple_FunctionImport"; const string testName = "UndoRedo." + typePrefix; ExecuteUndoRedoTest( testName, "NorthwindModel.edmx", (commandProcessorContext, artifact) => { var dte = VsIdeTestHostContext.Dte; var conceptualEntityContainer = (ConceptualEntityContainer)artifact.ConceptualModel().EntityContainers().Single(); var entityContainerMapping = artifact.MappingModel().EntityContainerMappings().Single(); Action<Function, string, object> createFunctionImport = (function, functionImportName, returnType) => { var functionImportCmd = new CreateFunctionImportCommand( conceptualEntityContainer, function, functionImportName, returnType); var functionImportMappingCmd = new CreateFunctionImportMappingCommand( entityContainerMapping, function, functionImportCmd.Id); functionImportMappingCmd.AddPreReqCommand(functionImportCmd); new CommandProcessor(commandProcessorContext, functionImportCmd, functionImportMappingCmd) .Invoke(); }; // CREATE THREE FUNCTION IMPORTS (don't undo/redo yet) var function1 = artifact.GetFreshStorageFunction("GetFreightCost"); createFunctionImport(function1, "a", Resources.NoneDisplayValueUsedForUX); Assert.AreEqual( "NorthwindModel.Store.GetFreightCost", artifact.GetFreshFunctionMapping("a").FunctionName.RefName); Assert.AreEqual( Resources.NoneDisplayValueUsedForUX, ((DefaultableValue<string>)artifact.GetFreshFunctionImport("a").ReturnType).Value); createFunctionImport(function1, "aa", "Int16"); Assert.AreEqual( "NorthwindModel.Store.GetFreightCost", artifact.GetFreshFunctionMapping("aa").FunctionName.RefName); Assert.AreEqual( "Collection(Int16)", ((DefaultableValue<string>)artifact.GetFreshFunctionImport("aa").ReturnType).Value); var function2 = artifact.GetFreshStorageFunction("Sales_by_Year"); createFunctionImport(function2, "aaa", artifact.GetFreshConceptualEntity("Orders")); Assert.AreEqual( "NorthwindModel.Store.Sales_by_Year", artifact.GetFreshFunctionMapping("aaa").FunctionName.RefName); Assert.AreEqual( "Collection(NorthwindModel.Orders)", ((SingleItemBinding<EntityType>)artifact.GetFreshFunctionImport("aaa").ReturnType).RefName); // CHANGE RETURN TYPE (don't undo/redo yet) var functionImport = artifact.GetFreshFunctionImport("aaa"); new CommandProcessor( commandProcessorContext, new ChangeFunctionImportCommand( conceptualEntityContainer, functionImport, function2, "aaa", functionImport.IsComposable.Value, /* changeReturnType */ true, Resources.NoneDisplayValueUsedForUX) ).Invoke(); Assert.AreEqual( "NorthwindModel.Store.Sales_by_Year", artifact.GetFreshFunctionMapping("aaa").FunctionName.RefName, "Mapping must not be changed."); Assert.AreEqual( Resources.NoneDisplayValueUsedForUX, ((DefaultableValue<string>)artifact.GetFreshFunctionImport("aaa").ReturnType).Value); // CHANGE STORED PROCEDURE NAME (don't undo/redo yet) functionImport = artifact.GetFreshFunctionImport("aaa"); new CommandProcessor( commandProcessorContext, new ChangeFunctionImportCommand( conceptualEntityContainer, functionImport, null, "aaa", functionImport.IsComposable.Value, false, null)).Invoke(); Assert.IsNotNull(artifact.GetFreshFunctionImport("aaa")); Assert.AreEqual( Resources.NoneDisplayValueUsedForUX, ((DefaultableValue<string>)artifact.GetFreshFunctionImport("aaa").ReturnType).Value); Assert.IsNull(artifact.GetFreshFunctionMapping("aaa"), "Mapping should have been deleted."); Assert.IsNotNull( artifact.GetFreshStorageFunction("Sales_by_Year"), "Function should not have been deleted."); // UNDO/REDO 5 LEVELS // undo five times (Undo Change Sproc, Change Return Type, Create FI3, Create FI2, Create FI1) dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), UndoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), UndoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), UndoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), UndoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), UndoCommand); Assert.IsFalse(conceptualEntityContainer.FunctionImports().Any()); Assert.IsFalse(entityContainerMapping.FunctionImportMappings().Any()); // redo five times (Redo Create FI1, FI2, FI3, Change Return Type, Change Sproc) dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), RedoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), RedoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), RedoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), RedoCommand); dte.ExecuteCommandForOpenDocument(artifact.LocalPath(), RedoCommand); Assert.AreEqual(3, conceptualEntityContainer.FunctionImports().Count()); Assert.AreEqual(2, entityContainerMapping.FunctionImportMappings().Count()); Assert.AreEqual( "NorthwindModel.Store.GetFreightCost", artifact.GetFreshFunctionMapping("a").FunctionName.RefName); Assert.AreEqual( "NorthwindModel.Store.GetFreightCost", artifact.GetFreshFunctionMapping("aa").FunctionName.RefName); }); }); }
protected override void InvokeInternal(CommandProcessorContext cpc) { var artifact = cpc.EditingContext.GetEFArtifactService().Artifact; if (null == artifact) { Debug.Fail("null artifact not allowed"); return; } // safety check, this should never be hit Debug.Assert(_schemaProcedure != null, "InvokeInternal is called when _schemaProcedure is null"); if (null == _schemaProcedure) { throw new InvalidOperationException("InvokeInternal is called when _schemaProcedure is null."); } var cModel = artifact.ConceptualModel(); if (null == cModel) { Debug.Fail("ConceptualEntityModel not allowed"); return; } var cContainer = cModel.FirstEntityContainer as ConceptualEntityContainer; if (null == cContainer) { Debug.Fail("ConceptualEntityContainer not allowed"); return; } var sModel = artifact.StorageModel(); if (null == sModel) { Debug.Fail("null StorageEntityModel not allowed"); return; } // determine matching Function var funcObj = DatabaseObject.CreateFromSchemaProcedure(_schemaProcedure); var function = ModelHelper.FindFunction(sModel, funcObj); if (null == function) { // in some error scenarios where the model has not been properly created we can be asked to create a FunctionImport for a Function which does not exist // if so just return without creating return; } // do not produce FunctionImports for composable Functions unless _shouldCreateComposableFunctionImport is true if (false == _shouldCreateComposableFunctionImport && function.IsComposable.Value) { return; } // determine FunctionImport name and make sure it is unique var functionImportName = OverrideNameValue; if (String.IsNullOrWhiteSpace(functionImportName)) { if (null == function.LocalName || string.IsNullOrEmpty(function.LocalName.Value)) { Debug.Fail("null or empty LocalName attribute for matching Function " + function); return; } functionImportName = ModelHelper.GetUniqueName(typeof(FunctionImport), cContainer, function.LocalName.Value); } else { #if DEBUG string errorMessage; var isUnique = ModelHelper.IsUniqueName(typeof(FunctionImport), cContainer, functionImportName, false, out errorMessage); Debug.Assert(isUnique, "If we gave CreateMatchingFunctionImportCommand a name, it should have been unique"); #endif } object returnType = null; ComplexType existingComplexTypeReturnType = null; if (OverrideReturnTypeValue == null) { // get return type of the Function returnType = ConstructReturnType(_schemaProcedure, cModel, sModel, functionImportName); if (null == returnType) { Debug.Fail("cannot determine return type for schemaProcedure " + _schemaProcedure); return; } } else { if (OverrideReturnTypeValue.Equals(ModelConstants.NoneValue, StringComparison.Ordinal)) { returnType = Resources.NoneDisplayValueUsedForUX; } else { var rawValue = ModelHelper.UnwrapCollectionAroundFunctionImportReturnType(OverrideReturnTypeValue); // Here we attempt to find the corresponding ReturnType for the given ReturnTypeOverride. // The ReturnTypeOverride will be specified as the actual XAttribute value of the return type if (OverrideEntitySetValue != null) { if (ModelHelper.FindEntitySet(cpc.Artifact.ConceptualModel(), OverrideEntitySetValue) != null) { // ReturnType is an EntityType returnType = ModelHelper.FindEntityTypeViaSymbol(cpc.Artifact.ConceptualModel(), rawValue); } } else if (!ModelHelper.AllPrimitiveTypes(artifact.SchemaVersion).Contains(rawValue)) { // ReturnType is a ComplexType existingComplexTypeReturnType = ModelHelper.FindComplexType(cpc.Artifact.ConceptualModel(), rawValue); returnType = existingComplexTypeReturnType; } else { returnType = rawValue; } } } // Composable functions that do not return collections (e.g. scalar valued functions) are not supported // and should not be imported to the conceptual model if (Resources.NoneDisplayValueUsedForUX.Equals(returnType) && function.IsComposable.Value) { return; } // list of commands to be executed IList <Command> commands = new List <Command>(); // if return type is the name of a ComplexType then create a new matching ComplexType CreateComplexTypeCommand createComplexTypeCommand = null; if (OverrideReturnTypeValue == null && returnType is string && false == Resources.NoneDisplayValueUsedForUX.Equals(returnType)) { createComplexTypeCommand = AddCreateComplexTypeCommands(sModel, returnType as string, _schemaProcedure.RawColumns, commands); } // if we created a ComplexType above then pass that as a pre-req to the CreateFunctionImport command, // otherwise just create the FunctionImport without the pre-req CreateFunctionImportCommand cmdFuncImp; if (createComplexTypeCommand == null) { if (returnType is EdmType) { // For the case where the FunctionImport should have a return type which is not a Complex Type but // simply a C-side primitive type we have to pass the _name_ of the C-side primitive type to // CreateFunctionImportCommand, rather than the type itself returnType = (returnType as EdmType).Name; } cmdFuncImp = new CreateFunctionImportCommand(cContainer, function, functionImportName, returnType); } else { cmdFuncImp = new CreateFunctionImportCommand(cContainer, function, functionImportName, createComplexTypeCommand); } commands.Add(cmdFuncImp); // now create the FunctionImportMapping to map the S-side Function to the C-side FunctionImport if (null != artifact.MappingModel() && null != artifact.MappingModel().FirstEntityContainerMapping) { var cmdFuncImpMapping = new CreateFunctionImportMappingCommand( artifact.MappingModel().FirstEntityContainerMapping, function, cmdFuncImp.Id); cmdFuncImpMapping.AddPreReqCommand(cmdFuncImp); commands.Add(cmdFuncImpMapping); IDictionary <string, string> mapPropertyNameToColumnName = null; if (_schemaProcedure != null) { mapPropertyNameToColumnName = ModelHelper.ConstructComplexTypePropertyNameToColumnNameMapping( _schemaProcedure.RawColumns.Select(c => c.Name).ToList()); } // Create explicit function-import result type mapping if the return type is a complex type. if (createComplexTypeCommand != null) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, createComplexTypeCommand) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } else if (OverrideReturnTypeValue != null && existingComplexTypeReturnType != null) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, existingComplexTypeReturnType) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } } // now invoke the list of commands if (null != commands) { var cp = new CommandProcessor(cpc, commands); cp.Invoke(); // assign the generated FunctionImport so this command can be used as input for others _generatedFunctionImport = cmdFuncImp.FunctionImport; } }
internal static FunctionImport CreateFunctionImport( EditingContext editingContext, EFArtifact artifact, Function selectedSproc, StorageEntityModel sModel, ConceptualEntityModel cModel, ConceptualEntityContainer cContainer, EntityType entityType, string originatingId) { FunctionImport functionImportResult = null; Debug.Assert(editingContext != null, "editingContext should not be null"); Debug.Assert(artifact != null, "artifact should not be null"); Debug.Assert(!string.IsNullOrEmpty(originatingId), "originatingId should not be null or empty"); // show dialog appropriate to framework version var result = ShowNewFunctionImportDialog( selectedSproc, null /* selectedSprocName Parameter */, sModel, cModel, cContainer, DialogsResource.NewFunctionImportDialog_AddFunctionImportTitle, entityType); // if user selected OK on the dialog then create the FunctionImport if (DialogResult.OK == result.DialogResult) { var commands = new Collection<Command>(); CreateComplexTypeCommand createComplexTypeCommand = null; // Make the decision based on what is returned by the dialog. // If return type is a string and result schema is not null, that means the user would like create a new complex type for the function import return. if (result.ReturnType is string && result.Schema != null) { createComplexTypeCommand = CreateMatchingFunctionImportCommand.AddCreateComplexTypeCommands( sModel, result.ReturnType as string, result.Schema.RawColumns, commands); } // If ReturnType is a complex type and result schema is not null, the complex type needs to be updated to be in sync with schema columns. else if (result.ReturnType is ComplexType && result.Schema != null) { var complexType = result.ReturnType as ComplexType; var propertiesDictionary = complexType.Properties().ToDictionary(p => p.LocalName.Value); CreateMatchingFunctionImportCommand.AddChangeComplexTypePropertiesCommands( complexType, propertiesDictionary, result.Schema.RawColumns, commands); } CreateFunctionImportCommand cmdFuncImp; if (createComplexTypeCommand == null) { cmdFuncImp = new CreateFunctionImportCommand(cContainer, result.Function, result.FunctionName, result.ReturnType); } else { // Pass in the pre-req command to create complex type to the command. cmdFuncImp = new CreateFunctionImportCommand(cContainer, result.Function, result.FunctionName, createComplexTypeCommand); } commands.Add(cmdFuncImp); // now add a FunctionImport and a FunctionImportMapping (if appropriate) if (artifact.MappingModel() != null && artifact.MappingModel().FirstEntityContainerMapping != null) { var cmdFuncImpMapping = new CreateFunctionImportMappingCommand( artifact.MappingModel().FirstEntityContainerMapping, result.Function, cmdFuncImp.Id); cmdFuncImpMapping.AddPreReqCommand(cmdFuncImp); commands.Add(cmdFuncImpMapping); IDictionary<string, string> mapPropertyNameToColumnName = null; if (result.Schema != null) { mapPropertyNameToColumnName = ModelHelper.ConstructComplexTypePropertyNameToColumnNameMapping( result.Schema.Columns.Select(c => c.Name).ToList()); } // Create explicit function-import result type mapping if the return type is a complex type. if (createComplexTypeCommand != null) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, createComplexTypeCommand) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } else if (result.ReturnType is ComplexType) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, result.ReturnType as ComplexType) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } } var cp = new CommandProcessor(editingContext, originatingId, Resources.Tx_CreateFunctionImport, commands); cp.Invoke(); functionImportResult = cmdFuncImp.FunctionImport; NavigateToFunction(functionImportResult); } return functionImportResult; }
protected override void InvokeInternal(CommandProcessorContext cpc) { var artifact = cpc.EditingContext.GetEFArtifactService().Artifact; if (null == artifact) { Debug.Fail("null artifact not allowed"); return; } // safety check, this should never be hit Debug.Assert(_schemaProcedure != null, "InvokeInternal is called when _schemaProcedure is null"); if (null == _schemaProcedure) { throw new InvalidOperationException("InvokeInternal is called when _schemaProcedure is null."); } var cModel = artifact.ConceptualModel(); if (null == cModel) { Debug.Fail("ConceptualEntityModel not allowed"); return; } var cContainer = cModel.FirstEntityContainer as ConceptualEntityContainer; if (null == cContainer) { Debug.Fail("ConceptualEntityContainer not allowed"); return; } var sModel = artifact.StorageModel(); if (null == sModel) { Debug.Fail("null StorageEntityModel not allowed"); return; } // determine matching Function var funcObj = DatabaseObject.CreateFromSchemaProcedure(_schemaProcedure); var function = ModelHelper.FindFunction(sModel, funcObj); if (null == function) { // in some error scenarios where the model has not been properly created we can be asked to create a FunctionImport for a Function which does not exist // if so just return without creating return; } // do not produce FunctionImports for composable Functions unless _shouldCreateComposableFunctionImport is true if (false == _shouldCreateComposableFunctionImport && function.IsComposable.Value) { return; } // determine FunctionImport name and make sure it is unique var functionImportName = OverrideNameValue; if (String.IsNullOrWhiteSpace(functionImportName)) { if (null == function.LocalName || string.IsNullOrEmpty(function.LocalName.Value)) { Debug.Fail("null or empty LocalName attribute for matching Function " + function); return; } functionImportName = ModelHelper.GetUniqueName(typeof(FunctionImport), cContainer, function.LocalName.Value); } else { #if DEBUG string errorMessage; var isUnique = ModelHelper.IsUniqueName(typeof(FunctionImport), cContainer, functionImportName, false, out errorMessage); Debug.Assert(isUnique, "If we gave CreateMatchingFunctionImportCommand a name, it should have been unique"); #endif } object returnType = null; ComplexType existingComplexTypeReturnType = null; if (OverrideReturnTypeValue == null) { // get return type of the Function returnType = ConstructReturnType(_schemaProcedure, cModel, sModel, functionImportName); if (null == returnType) { Debug.Fail("cannot determine return type for schemaProcedure " + _schemaProcedure); return; } } else { if (OverrideReturnTypeValue.Equals(ModelConstants.NoneValue, StringComparison.Ordinal)) { returnType = Resources.NoneDisplayValueUsedForUX; } else { var rawValue = ModelHelper.UnwrapCollectionAroundFunctionImportReturnType(OverrideReturnTypeValue); // Here we attempt to find the corresponding ReturnType for the given ReturnTypeOverride. // The ReturnTypeOverride will be specified as the actual XAttribute value of the return type if (OverrideEntitySetValue != null) { if (ModelHelper.FindEntitySet(cpc.Artifact.ConceptualModel(), OverrideEntitySetValue) != null) { // ReturnType is an EntityType returnType = ModelHelper.FindEntityTypeViaSymbol(cpc.Artifact.ConceptualModel(), rawValue); } } else if (!ModelHelper.AllPrimitiveTypes(artifact.SchemaVersion).Contains(rawValue)) { // ReturnType is a ComplexType existingComplexTypeReturnType = ModelHelper.FindComplexType(cpc.Artifact.ConceptualModel(), rawValue); returnType = existingComplexTypeReturnType; } else { returnType = rawValue; } } } // Composable functions that do not return collections (e.g. scalar valued functions) are not supported // and should not be imported to the conceptual model if (Resources.NoneDisplayValueUsedForUX.Equals(returnType) && function.IsComposable.Value) { return; } // list of commands to be executed IList<Command> commands = new List<Command>(); // if return type is the name of a ComplexType then create a new matching ComplexType CreateComplexTypeCommand createComplexTypeCommand = null; if (OverrideReturnTypeValue == null && returnType is string && false == Resources.NoneDisplayValueUsedForUX.Equals(returnType)) { createComplexTypeCommand = AddCreateComplexTypeCommands(sModel, returnType as string, _schemaProcedure.RawColumns, commands); } // if we created a ComplexType above then pass that as a pre-req to the CreateFunctionImport command, // otherwise just create the FunctionImport without the pre-req CreateFunctionImportCommand cmdFuncImp; if (createComplexTypeCommand == null) { if (returnType is EdmType) { // For the case where the FunctionImport should have a return type which is not a Complex Type but // simply a C-side primitive type we have to pass the _name_ of the C-side primitive type to // CreateFunctionImportCommand, rather than the type itself returnType = (returnType as EdmType).Name; } cmdFuncImp = new CreateFunctionImportCommand(cContainer, function, functionImportName, returnType); } else { cmdFuncImp = new CreateFunctionImportCommand(cContainer, function, functionImportName, createComplexTypeCommand); } commands.Add(cmdFuncImp); // now create the FunctionImportMapping to map the S-side Function to the C-side FunctionImport if (null != artifact.MappingModel() && null != artifact.MappingModel().FirstEntityContainerMapping) { var cmdFuncImpMapping = new CreateFunctionImportMappingCommand( artifact.MappingModel().FirstEntityContainerMapping, function, cmdFuncImp.Id); cmdFuncImpMapping.AddPreReqCommand(cmdFuncImp); commands.Add(cmdFuncImpMapping); IDictionary<string, string> mapPropertyNameToColumnName = null; if (_schemaProcedure != null) { mapPropertyNameToColumnName = ModelHelper.ConstructComplexTypePropertyNameToColumnNameMapping( _schemaProcedure.RawColumns.Select(c => c.Name).ToList()); } // Create explicit function-import result type mapping if the return type is a complex type. if (createComplexTypeCommand != null) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, createComplexTypeCommand) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } else if (OverrideReturnTypeValue != null && existingComplexTypeReturnType != null) { commands.Add( new CreateFunctionImportTypeMappingCommand(cmdFuncImpMapping, existingComplexTypeReturnType) { CreateDefaultScalarProperties = true, PropertyNameToColumnNameMap = mapPropertyNameToColumnName }); } } // now invoke the list of commands if (null != commands) { var cp = new CommandProcessor(cpc, commands); cp.Invoke(); // assign the generated FunctionImport so this command can be used as input for others _generatedFunctionImport = cmdFuncImp.FunctionImport; } }