Beispiel #1
0
        /// <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);
                                });
                    });
        }
Beispiel #4
0
        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;
            }
        }