示例#1
0
        public void WriteFunctionMapping(
            string functionElement, StorageModificationFunctionMapping functionMapping, bool associationSetMapping = false)
        {
            DebugCheck.NotNull(functionMapping);

            _xmlWriter.WriteStartElement(functionElement);
            _xmlWriter.WriteAttributeString(StorageMslConstructs.FunctionNameAttribute, functionMapping.Function.FullName);

            if (functionMapping.RowsAffectedParameter != null)
            {
                _xmlWriter.WriteAttributeString(
                    StorageMslConstructs.RowsAffectedParameterAttribute,
                    functionMapping.RowsAffectedParameter.Name);
            }

            if (!associationSetMapping)
            {
                WritePropertyParameterBindings(functionMapping.ParameterBindings);
                WriteAssociationParameterBindings(functionMapping.ParameterBindings);

                if (functionMapping.ResultBindings != null)
                {
                    WriteResultBindings(functionMapping.ResultBindings);
                }
            }
            else
            {
                WriteAssociationSetMappingParameterBindings(functionMapping.ParameterBindings);
            }

            _xmlWriter.WriteEndElement();
        }
        public void Configure_association_set_should_call_configure_function_configurations()
        {
            var modificationFunctionsConfiguration = new ModificationFunctionsConfiguration();

            var mockModificationFunctionConfiguration = new Mock <ModificationFunctionConfiguration>();

            modificationFunctionsConfiguration.Insert(mockModificationFunctionConfiguration.Object);
            modificationFunctionsConfiguration.Delete(mockModificationFunctionConfiguration.Object);

            var entitySet = new EntitySet();

            entitySet.ChangeEntityContainerWithoutCollectionFixup(new EntityContainer("C", DataSpace.CSpace));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      new EntityType("E", "N", DataSpace.CSpace),
                      new EdmFunction("F", "N", DataSpace.SSpace),
                      new StorageModificationFunctionParameterBinding[0],
                      null,
                      null);

            modificationFunctionsConfiguration.Configure(
                new StorageAssociationSetModificationFunctionMapping(
                    new AssociationSet("AS", new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace)),
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping),
                ProviderRegistry.Sql2008_ProviderManifest);

            mockModificationFunctionConfiguration
            .Verify(
                m => m.Configure(storageModificationFunctionMapping, It.IsAny <DbProviderManifest>()),
                Times.Exactly(2));
        }
示例#3
0
        private void ConfigureRowsAffectedParameter(
            StorageModificationFunctionMapping modificationFunctionMapping, DbProviderManifest providerManifest)
        {
            DebugCheck.NotNull(modificationFunctionMapping);
            DebugCheck.NotNull(providerManifest);

            if (!string.IsNullOrWhiteSpace(_rowsAffectedParameter))
            {
                if (modificationFunctionMapping.RowsAffectedParameter == null)
                {
                    var rowsAffectedParameter
                        = new FunctionParameter(
                              "_RowsAffected_",
                              providerManifest.GetStoreType(
                                  TypeUsage.CreateDefaultTypeUsage(
                                      PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32))),
                              ParameterMode.Out);

                    modificationFunctionMapping.Function.AddParameter(rowsAffectedParameter);
                    modificationFunctionMapping.RowsAffectedParameter = rowsAffectedParameter;
                }

                modificationFunctionMapping.RowsAffectedParameter.Name = _rowsAffectedParameter;

                _configuredParameters.Add(modificationFunctionMapping.RowsAffectedParameter);
            }
        }
        public void Configure_should_call_configure_function_configurations()
        {
            var modificationFunctionsConfiguration = new ModificationFunctionsConfiguration();

            var mockModificationFunctionConfiguration = new Mock <ModificationFunctionConfiguration>();

            modificationFunctionsConfiguration.Insert(mockModificationFunctionConfiguration.Object);
            modificationFunctionsConfiguration.Update(mockModificationFunctionConfiguration.Object);
            modificationFunctionsConfiguration.Delete(mockModificationFunctionConfiguration.Object);

            var entitySet = new EntitySet();

            entitySet.ChangeEntityContainerWithoutCollectionFixup(new EntityContainer("C", DataSpace.CSpace));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      new EntityType("E", "N", DataSpace.CSpace),
                      new EdmFunction("F", "N", DataSpace.SSpace),
                      new StorageModificationFunctionParameterBinding[0],
                      null,
                      null);

            modificationFunctionsConfiguration.Configure(
                new StorageEntityTypeModificationFunctionMapping(
                    new EntityType("E", "N", DataSpace.CSpace),
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping));

            mockModificationFunctionConfiguration
            .Verify(m => m.Configure(storageModificationFunctionMapping), Times.Exactly(3));
        }
        private DbModificationCommandTree ConvertInternal(DbInsertCommandTree commandTree)
        {
            DebugCheck.NotNull(commandTree);

            if (_currentFunctionMapping == null)
            {
                _currentFunctionMapping
                    = _entityTypeModificationFunctionMapping != null
                        ? _entityTypeModificationFunctionMapping.InsertFunctionMapping
                        : _associationSetModificationFunctionMapping.InsertFunctionMapping;

                var firstTable
                    = ((DbScanExpression)commandTree.Target.Expression).Target.ElementType;

                _storeGeneratedKeys
                    = firstTable.KeyProperties
                      .Where(p => p.IsStoreGeneratedIdentity)
                      .ToList();
            }

            _nextStoreGeneratedKey = 0;

            return
                (new DbInsertCommandTree(
                     commandTree.MetadataWorkspace,
                     commandTree.DataSpace,
                     commandTree.Target,
                     VisitSetClauses(commandTree.SetClauses),
                     commandTree.Returning != null ? commandTree.Returning.Accept(this) : null));
        }
        public void Configure_should_introduce_rows_affected_parameter_when_configured()
        {
            var modificationFunctionConfiguration = new ModificationFunctionConfiguration();

            modificationFunctionConfiguration.RowsAffectedParameter("rows_affected");

            var entitySet = new EntitySet();

            entitySet.ChangeEntityContainerWithoutCollectionFixup(new EntityContainer("C", DataSpace.CSpace));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      new EntityType("E", "N", DataSpace.CSpace),
                      new EdmFunction("F", "N", DataSpace.SSpace),
                      new StorageModificationFunctionParameterBinding[0],
                      null,
                      null);

            modificationFunctionConfiguration.Configure(
                storageModificationFunctionMapping,
                ProviderRegistry.Sql2008_ProviderManifest);

            Assert.Equal("rows_affected", storageModificationFunctionMapping.RowsAffectedParameterName);
        }
示例#7
0
        private void ConfigureSchema(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            DebugCheck.NotNull(modificationFunctionMapping);

            if (!string.IsNullOrWhiteSpace(_schema))
            {
                modificationFunctionMapping.Function.Schema = _schema;
            }
        }
示例#8
0
        private void ConfigureName(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            DebugCheck.NotNull(modificationFunctionMapping);

            if (!string.IsNullOrWhiteSpace(_name))
            {
                modificationFunctionMapping.Function.StoreFunctionNameAttribute = _name;
            }
        }
 /// <summary>
 /// Initialize a new function command. Initializes the command object.
 /// </summary>
 /// <param name="functionMapping">Function mapping metadata</param>
 /// <param name="translator">Translator</param>
 /// <param name="stateEntries">State entries handled by this operation.</param>
 /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
 internal FunctionUpdateCommand(
     StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
     ReadOnlyCollection<IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry)
     : this(translator, stateEntries, stateEntry,
         translator.GenerateCommandDefinition(functionMapping).CreateCommand())
 {
     Contract.Requires(functionMapping != null);
     Contract.Requires(translator != null);
     Contract.Requires(stateEntries != null);
 }
示例#10
0
 /// <summary>
 ///     Initialize a new function command. Initializes the command object.
 /// </summary>
 /// <param name="functionMapping"> Function mapping metadata </param>
 /// <param name="translator"> Translator </param>
 /// <param name="stateEntries"> State entries handled by this operation. </param>
 /// <param name="stateEntry"> 'Root' state entry being handled by this function. </param>
 internal FunctionUpdateCommand(
     StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
     ReadOnlyCollection <IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry)
     : this(translator, stateEntries, stateEntry,
            translator.GenerateCommandDefinition(functionMapping).CreateCommand())
 {
     DebugCheck.NotNull(functionMapping);
     DebugCheck.NotNull(translator);
     DebugCheck.NotNull(stateEntries);
 }
        public void WriteFunctionMapping_should_write_simple_parameter_and_result_bindings_and_rows_affected_parameter()
        {
            var fixture = new Fixture();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet  = new EntitySet("ES", "S", null, null, entityType);

            new EntityContainer("EC", DataSpace.SSpace).AddEntitySetBase(entitySet);

            var property = new EdmProperty("M");

            var typeUsage = TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      entityType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      new[]
            {
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        typeUsage,
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new[] { property },
                        null),
                    true),
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P_Original",
                        typeUsage,
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new[] { property },
                        null),
                    false)
            },
                      new FunctionParameter("RowsAffected", typeUsage, ParameterMode.Out),
                      new[]
            {
                new StorageModificationFunctionResultBinding("C", property)
            });

            fixture.Writer.WriteFunctionMapping("InsertFunction", storageModificationFunctionMapping);

            Assert.Equal(
                @"<InsertFunction FunctionName=""N.F"" RowsAffectedParameter=""RowsAffected"">
  <ScalarProperty Name=""M"" ParameterName=""P"" Version=""Current"" />
  <ScalarProperty Name=""M"" ParameterName=""P_Original"" Version=""Original"" />
  <ResultBinding Name=""M"" ColumnName=""C"" />
</InsertFunction>",
                fixture.ToString());
        }
 /// <summary>
 ///     Initialize a new function command. Initializes the command object.
 /// </summary>
 /// <param name="functionMapping"> Function mapping metadata </param>
 /// <param name="translator"> Translator </param>
 /// <param name="stateEntries"> State entries handled by this operation. </param>
 /// <param name="stateEntry"> 'Root' state entry being handled by this function. </param>
 internal FunctionUpdateCommand(
     StorageModificationFunctionMapping functionMapping,
     UpdateTranslator translator,
     ReadOnlyCollection<IEntityStateEntry> stateEntries,
     ExtractedStateEntry stateEntry)
     : this(translator, stateEntries, stateEntry,
         translator.GenerateCommandDefinition(functionMapping).CreateCommand())
 {
     DebugCheck.NotNull(functionMapping);
     DebugCheck.NotNull(translator);
     DebugCheck.NotNull(stateEntries);
 }
示例#13
0
        public void GetComplexParameterBindings_should_return_all_complex_parameter_bindings_for_type()
        {
            var databaseMapping
                = new DbDatabaseMapping()
                  .Initialize(
                      new EdmModel(DataSpace.CSpace),
                      new EdmModel(DataSpace.SSpace));

            var entityType       = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet        = databaseMapping.Model.AddEntitySet("ES", entityType);
            var entitySetMapping = databaseMapping.AddEntitySetMapping(entitySet);

            var complexType1 = new ComplexType();

            complexType1.Annotations.SetClrType(typeof(string));

            var complexType2 = new ComplexType();

            complexType2.Annotations.SetClrType(typeof(object));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      entityType,
                      new EdmFunction("F", "N", DataSpace.SSpace),
                      new[]
            {
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(),
                    new StorageModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    EdmProperty.Complex("C1", complexType1),
                    EdmProperty.Complex("C2", complexType2),
                    new EdmProperty("M")
                },
                        null),
                    true
                    )
            },
                      null,
                      null);

            entitySetMapping.AddModificationFunctionMapping(
                new StorageEntityTypeModificationFunctionMapping(
                    entityType,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping));

            Assert.Equal(3, databaseMapping.GetComplexParameterBindings(typeof(string)).Count());
            Assert.Equal(3, databaseMapping.GetComplexParameterBindings(typeof(object)).Count());
        }
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry)
            {
                if (null == m_mapping)
                {
                    return(null);
                }

                bool isInsert = EntityState.Added == stateEntry.State;

                EntityUtil.ValidateNecessaryModificationFunctionMapping(
                    isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping,
                    isInsert ? "Insert" : "Delete",
                    stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name);

                // initialize a new command
                StorageModificationFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping;
                FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry);

                // extract the relationship values from the state entry
                PropagatorResult recordResult;

                if (isInsert)
                {
                    recordResult = stateEntry.Current;
                }
                else
                {
                    recordResult = stateEntry.Original;
                }

                // bind parameters
                foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    // extract the relationship information
                    Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " +
                                 "path should include the relationship end and key property only");

                    EdmProperty          keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                    AssociationEndMember endMember   = (AssociationEndMember)parameterBinding.MemberPath.Members[1];

                    // get the end member
                    PropagatorResult endResult = recordResult.GetMemberValue(endMember);
                    PropagatorResult keyResult = endResult.GetMemberValue(keyProperty);

                    command.SetParameterValue(keyResult, parameterBinding, translator);
                }
                // add rows affected output parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);

                return(command);
            }
示例#15
0
        public virtual void Configure(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            DebugCheck.NotNull(modificationFunctionMapping);

            _configuredParameters = new List <FunctionParameter>();

            ConfigureName(modificationFunctionMapping);
            ConfigureSchema(modificationFunctionMapping);
            ConfigureRowsAffectedParameter(modificationFunctionMapping);
            ConfigureParameters(modificationFunctionMapping);
            ConfigureResultBindings(modificationFunctionMapping);
        }
        public void WriteFunctionMapping_should_write_association_end_bindings()
        {
            var fixture = new Fixture();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet  = new EntitySet("ES", "S", null, null, entityType);

            new EntityContainer("EC", DataSpace.SSpace).AddEntitySetBase(entitySet);
            var associationSet = new AssociationSet("AS", new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace));

            var associationEndMember1 = new AssociationEndMember("Source", new EntityType("E", "N", DataSpace.CSpace));

            associationSet.AddAssociationSetEnd(new AssociationSetEnd(entitySet, associationSet, associationEndMember1));

            var associationEndMember2 = new AssociationEndMember("Target", new EntityType("E", "N", DataSpace.CSpace));

            associationSet.AddAssociationSetEnd(new AssociationSetEnd(entitySet, associationSet, associationEndMember2));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      entityType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      new[]
            {
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    new EdmProperty("K"),
                    associationEndMember1
                },
                        associationSet),
                    true)
            },
                      null,
                      null);

            fixture.Writer.WriteFunctionMapping("InsertFunction", storageModificationFunctionMapping);

            Assert.Equal(
                @"<InsertFunction FunctionName=""N.F"">
  <AssociationEnd AssociationSet=""AS"" From=""Source"" To=""Target"">
    <ScalarProperty Name=""K"" ParameterName=""P"" Version=""Current"" />
  </AssociationEnd>
</InsertFunction>",
                fixture.ToString());
        }
示例#17
0
 internal static void ValidateNecessaryModificationFunctionMapping(
     StorageModificationFunctionMapping mapping, string currentState,
     IEntityStateEntry stateEntry, string type, string typeName)
 {
     if (null == mapping)
     {
         throw new UpdateException(
                   Strings.Update_MissingFunctionMapping(currentState, type, typeName),
                   null,
                   new List <IEntityStateEntry>
         {
             stateEntry
         }.Cast <ObjectStateEntry>().Distinct());
     }
 }
        private DbModificationCommandTree ConvertInternal(DbUpdateCommandTree commandTree)
        {
            DebugCheck.NotNull(commandTree);

            _currentFunctionMapping = _entityTypeModificationFunctionMapping.UpdateFunctionMapping;

            return
                (new DbUpdateCommandTree(
                     commandTree.MetadataWorkspace,
                     commandTree.DataSpace,
                     commandTree.Target,
                     commandTree.Predicate.Accept(this),
                     VisitSetClauses(commandTree.SetClauses),
                     commandTree.Returning != null ? commandTree.Returning.Accept(this) : null));
        }
        public IEnumerable <TCommandTree> Convert <TCommandTree>(
            IEnumerable <TCommandTree> modificationCommandTrees)
            where TCommandTree : DbModificationCommandTree
        {
            DebugCheck.NotNull(modificationCommandTrees);

            _currentFunctionMapping = null;
            _currentProperty        = null;
            _storeGeneratedKeys     = null;
            _nextStoreGeneratedKey  = 0;

            return(modificationCommandTrees
                   .Select(modificationCommandTree => ConvertInternal((dynamic)modificationCommandTree))
                   .Cast <TCommandTree>());
        }
        private DbModificationCommandTree ConvertInternal(DbDeleteCommandTree commandTree)
        {
            DebugCheck.NotNull(commandTree);

            _currentFunctionMapping
                = _entityTypeModificationFunctionMapping != null
                    ? _entityTypeModificationFunctionMapping.DeleteFunctionMapping
                    : _associationSetModificationFunctionMapping.DeleteFunctionMapping;

            return
                (new DbDeleteCommandTree(
                     commandTree.MetadataWorkspace,
                     commandTree.DataSpace,
                     commandTree.Target,
                     commandTree.Predicate.Accept(this)));
        }
        /// <summary>
        /// Initialize a new function command. Initializes the command object.
        /// </summary>
        /// <param name="functionMapping">Function mapping metadata</param>
        /// <param name="translator">Translator</param>
        /// <param name="stateEntries">State entries handled by this operation.</param>
        /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
        internal FunctionUpdateCommand(StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
            System.Collections.ObjectModel.ReadOnlyCollection<IEntityStateEntry> stateEntries,
            ExtractedStateEntry stateEntry)
            : base(stateEntry.Original, stateEntry.Current)
        {
            EntityUtil.CheckArgumentNull(functionMapping, "functionMapping");
            EntityUtil.CheckArgumentNull(translator, "translator");
            EntityUtil.CheckArgumentNull(stateEntries, "stateEntries");

            // populate the main state entry for error reporting
            m_stateEntries = stateEntries;

            // create a command
            DbCommandDefinition commandDefinition = translator.GenerateCommandDefinition(functionMapping);
            m_dbCommand = commandDefinition.CreateCommand();
        }
        private static void UniquifyFunctionName(
            DbDatabaseMapping databaseMapping,
            ModificationFunctionConfiguration modificationFunctionConfiguration,
            StorageModificationFunctionMapping functionMapping)
        {
            DebugCheck.NotNull(databaseMapping);
            DebugCheck.NotNull(functionMapping);

            if ((modificationFunctionConfiguration == null) ||
                string.IsNullOrWhiteSpace(modificationFunctionConfiguration.Name))
            {
                functionMapping.Function.Name
                    = databaseMapping.Database.Functions.Except(new[] { functionMapping.Function })
                      .UniquifyName(functionMapping.Function.Name);
            }
        }
示例#23
0
        private void ConfigureRowsAffectedParameter(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            DebugCheck.NotNull(modificationFunctionMapping);

            if (!string.IsNullOrWhiteSpace(_rowsAffectedParameter))
            {
                if (modificationFunctionMapping.RowsAffectedParameter == null)
                {
                    throw Error.NoRowsAffectedParameter(modificationFunctionMapping.Function.Name);
                }

                modificationFunctionMapping.RowsAffectedParameter.Name = _rowsAffectedParameter;

                _configuredParameters.Add(modificationFunctionMapping.RowsAffectedParameter);
            }
        }
        /// <summary>
        /// Initialize a new function command. Initializes the command object.
        /// </summary>
        /// <param name="functionMapping">Function mapping metadata</param>
        /// <param name="translator">Translator</param>
        /// <param name="stateEntries">State entries handled by this operation.</param>
        /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
        internal FunctionUpdateCommand(StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
                                       System.Collections.ObjectModel.ReadOnlyCollection <IEntityStateEntry> stateEntries,
                                       ExtractedStateEntry stateEntry)
            : base(stateEntry.Original, stateEntry.Current)
        {
            EntityUtil.CheckArgumentNull(functionMapping, "functionMapping");
            EntityUtil.CheckArgumentNull(translator, "translator");
            EntityUtil.CheckArgumentNull(stateEntries, "stateEntries");

            // populate the main state entry for error reporting
            m_stateEntries = stateEntries;

            // create a command
            DbCommandDefinition commandDefinition = translator.GenerateCommandDefinition(functionMapping);

            m_dbCommand = commandDefinition.CreateCommand();
        }
        public void WriteFunctionMapping_should_write_complex_parameter_bindings()
        {
            var fixture = new Fixture();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet  = new EntitySet("ES", "S", null, null, entityType);

            new EntityContainer("EC", DataSpace.SSpace).AddEntitySetBase(entitySet);

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      entityType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      new[]
            {
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new[]
                {
                    EdmProperty.Complex("C1", new ComplexType()),
                    EdmProperty.Complex("C2", new ComplexType()),
                    new EdmProperty("M")
                },
                        null),
                    true)
            },
                      null,
                      null);

            fixture.Writer.WriteFunctionMapping("InsertFunction", storageModificationFunctionMapping);

            Assert.Equal(
                @"<InsertFunction FunctionName=""N.F"">
  <ComplexProperty Name=""C1"" TypeName=""."">
    <ComplexProperty Name=""C2"" TypeName=""."">
      <ScalarProperty Name=""M"" ParameterName=""P"" Version=""Current"" />
    </ComplexProperty>
  </ComplexProperty>
</InsertFunction>",
                fixture.ToString());
        }
        public void WriteEntitySetMappingElement_should_write_modification_function_mappings()
        {
            var fixture = new Fixture();

            var entityType      = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet       = new EntitySet("ES", "S", null, null, entityType);
            var entityContainer = new EntityContainer("EC", DataSpace.SSpace);

            entityContainer.AddEntitySetBase(entitySet);

            var storageEntitySetMapping
                = new StorageEntitySetMapping(
                      entitySet,
                      new StorageEntityContainerMapping(entityContainer));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      entitySet,
                      entityType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      Enumerable.Empty <StorageModificationFunctionParameterBinding>(),
                      null,
                      null);

            storageEntitySetMapping.AddModificationFunctionMapping(
                new StorageEntityTypeModificationFunctionMapping(
                    entityType,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping));

            fixture.Writer.WriteEntitySetMappingElement(storageEntitySetMapping);

            Assert.Equal(
                @"<EntitySetMapping Name=""ES"">
  <EntityTypeMapping TypeName="".E"">
    <ModificationFunctionMapping>
      <InsertFunction FunctionName=""N.F"" />
      <UpdateFunction FunctionName=""N.F"" />
      <DeleteFunction FunctionName=""N.F"" />
    </ModificationFunctionMapping>
  </EntityTypeMapping>
</EntitySetMapping>",
                fixture.ToString());
        }
示例#27
0
        private void ConfigureResultBindings(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            DebugCheck.NotNull(modificationFunctionMapping);

            foreach (var keyValue in _resultBindings)
            {
                var propertyInfo = keyValue.Key;
                var columnName   = keyValue.Value;

                var resultBinding
                    = (modificationFunctionMapping
                       .ResultBindings ?? Enumerable.Empty <StorageModificationFunctionResultBinding>())
                      .SingleOrDefault(rb => propertyInfo.IsSameAs(rb.Property.GetClrPropertyInfo()));

                if (resultBinding == null)
                {
                    throw Error.ResultBindingNotFound(
                              propertyInfo.Name,
                              modificationFunctionMapping.Function.FunctionName);
                }

                resultBinding.ColumnName = columnName;
            }
        }
        // Generates and caches a command definition for the given function
        internal DbCommandDefinition GenerateCommandDefinition(StorageModificationFunctionMapping functionMapping)
        {
            if (null == m_modificationFunctionCommandDefinitions) 
            { 
                m_modificationFunctionCommandDefinitions = new Dictionary<StorageModificationFunctionMapping,DbCommandDefinition>();
            }
            DbCommandDefinition commandDefinition;
            if (!m_modificationFunctionCommandDefinitions.TryGetValue(functionMapping, out commandDefinition))
            {
                // synthesize a RowType for this mapping
                TypeUsage resultType = null;
                if (null != functionMapping.ResultBindings && 0 < functionMapping.ResultBindings.Count)
                {
                    List<EdmProperty> properties = new List<EdmProperty>(functionMapping.ResultBindings.Count);
                    foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings)
                    {
                        properties.Add(new EdmProperty(resultBinding.ColumnName, resultBinding.Property.TypeUsage));
                    }
                    RowType rowType = new RowType(properties);
                    CollectionType collectionType = new CollectionType(rowType);
                    resultType = TypeUsage.Create(collectionType);
                }

                // add function parameters
                IEnumerable<KeyValuePair<string, TypeUsage>> functionParams =
                    functionMapping.Function.Parameters.Select(paramInfo => new KeyValuePair<string, TypeUsage>(paramInfo.Name, paramInfo.TypeUsage));
                
                // construct DbFunctionCommandTree including implict return type
                DbFunctionCommandTree tree = new DbFunctionCommandTree(m_metadataWorkspace, DataSpace.SSpace,
                    functionMapping.Function, resultType, functionParams);
                                
                commandDefinition = m_providerServices.CreateCommandDefinition(tree);
            }
            return commandDefinition;
        }
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry)
            {
                var mapping = GetFunctionMapping(stateEntry);
                StorageEntityTypeModificationFunctionMapping typeMapping     = mapping.Item1;
                StorageModificationFunctionMapping           functionMapping = mapping.Item2;
                EntityKey entityKey = stateEntry.Source.EntityKey;

                var stateEntries = new HashSet <IEntityStateEntry> {
                    stateEntry.Source
                };

                // gather all referenced association ends
                var collocatedEntries =
                    // find all related entries corresponding to collocated association types
                    from end in functionMapping.CollocatedAssociationSetEnds
                    join candidateEntry in translator.GetRelationships(entityKey)
                    on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType
                    select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry);

                var currentReferenceEnds  = new Dictionary <AssociationEndMember, IEntityStateEntry>();
                var originalReferenceEnds = new Dictionary <AssociationEndMember, IEntityStateEntry>();

                foreach (var candidate in collocatedEntries)
                {
                    ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2);
                }

                // create function object
                FunctionUpdateCommand command;

                // consider the following scenario, we need to loop through all the state entries that is correlated with entity2 and make sure it is not changed.
                // entity1 <-- Independent Association <-- entity2 <-- Fk association <-- entity 3
                //                                           |
                //              entity4 <-- Fk association <--
                if (stateEntries.All(e => e.State == EntityState.Unchanged))
                {
                    // we shouldn't update the entity if it is unchanged, only update when referenced association is changed.
                    // if not, then this will trigger a fake update for principal end as describe in
                    command = null;
                }
                else
                {
                    command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry);

                    // bind all function parameters
                    BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds);

                    // interpret all result bindings
                    if (null != functionMapping.ResultBindings)
                    {
                        foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings)
                        {
                            PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property);
                            command.AddResultColumn(translator, resultBinding.ColumnName, result);
                        }
                    }
                }

                return(command);
            }
        public void WriteAssociationSetMapping_should_write_modification_function_mapping()
        {
            var fixture = new Fixture();

            var entityType = new EntityType("E", "N", DataSpace.CSpace);
            var entitySet  = new EntitySet("ES", "S", null, null, entityType);

            new EntityContainer("EC", DataSpace.SSpace).AddEntitySetBase(entitySet);
            var associationSet = new AssociationSet("AS", new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace));

            var associationEndMember1 = new AssociationEndMember("Source", new EntityType("E", "N", DataSpace.CSpace));

            associationSet.AddAssociationSetEnd(new AssociationSetEnd(entitySet, associationSet, associationEndMember1));

            var associationEndMember2 = new AssociationEndMember("Target", new EntityType("E", "N", DataSpace.CSpace));

            associationSet.AddAssociationSetEnd(new AssociationSetEnd(entitySet, associationSet, associationEndMember2));

            var storageModificationFunctionMapping
                = new StorageModificationFunctionMapping(
                      associationSet,
                      associationSet.ElementType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      new[]
            {
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    new EdmProperty("K"),
                    associationEndMember1
                },
                        associationSet),
                    true),
                new StorageModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new StorageModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    new EdmProperty("K"),
                    associationEndMember2
                },
                        associationSet),
                    false)
            },
                      null,
                      null);

            var associationSetMapping
                = new StorageAssociationSetMapping(
                      associationSet,
                      entitySet)
                {
                SourceEndMapping
                    = new StorageEndPropertyMapping
                    {
                    EndMember = associationEndMember1
                    },
                TargetEndMapping
                    = new StorageEndPropertyMapping
                    {
                    EndMember = associationEndMember2
                    },
                ModificationFunctionMapping = new StorageAssociationSetModificationFunctionMapping(
                    associationSet,
                    storageModificationFunctionMapping,
                    storageModificationFunctionMapping)
                };

            fixture.Writer.WriteAssociationSetMappingElement(associationSetMapping);

            Assert.Equal(
                @"<AssociationSetMapping Name=""AS"" TypeName="".A"" StoreEntitySet=""E"">
  <EndProperty Name=""Source"" />
  <EndProperty Name=""Target"" />
  <ModificationFunctionMapping>
    <InsertFunction FunctionName=""N.F"">
      <EndProperty Name=""Source"">
        <ScalarProperty Name=""K"" ParameterName=""P"" Version=""Current"" />
      </EndProperty>
      <EndProperty Name=""Target"">
        <ScalarProperty Name=""K"" ParameterName=""P"" Version=""Original"" />
      </EndProperty>
    </InsertFunction>
    <DeleteFunction FunctionName=""N.F"">
      <EndProperty Name=""Source"">
        <ScalarProperty Name=""K"" ParameterName=""P"" Version=""Current"" />
      </EndProperty>
      <EndProperty Name=""Target"">
        <ScalarProperty Name=""K"" ParameterName=""P"" Version=""Original"" />
      </EndProperty>
    </DeleteFunction>
  </ModificationFunctionMapping>
</AssociationSetMapping>",
                fixture.ToString());
        }
            // Walks through all parameter bindings in the function mapping and binds the parameters to the
            // requested properties of the given state entry.
            private static void BindFunctionParameters(
                UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageModificationFunctionMapping functionMapping,
                FunctionUpdateCommand command, Dictionary <AssociationEndMember, IEntityStateEntry> currentReferenceEnds,
                Dictionary <AssociationEndMember, IEntityStateEntry> originalReferenceEnds)
            {
                // bind all parameters
                foreach (var parameterBinding in functionMapping.ParameterBindings)
                {
                    PropagatorResult result;

                    // extract value
                    if (null != parameterBinding.MemberPath.AssociationSetEnd)
                    {
                        // find the relationship entry corresponding to the navigation
                        var endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember;
                        IEntityStateEntry relationshipEntry;
                        var hasTarget = parameterBinding.IsCurrent
                                            ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry)
                                            : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry);
                        if (!hasTarget)
                        {
                            if (endMember.RelationshipMultiplicity
                                == RelationshipMultiplicity.One)
                            {
                                var entitySetName      = stateEntry.Source.EntitySet.Name;
                                var associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name;
                                throw new UpdateException(
                                          Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName), null,
                                          command.GetStateEntries(translator).Cast <ObjectStateEntry>().Distinct());
                            }
                            else
                            {
                                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null);
                            }
                        }
                        else
                        {
                            // get the actual value
                            var relationshipResult = parameterBinding.IsCurrent
                                                         ? translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                                relationshipEntry, ModifiedPropertiesBehavior.AllModified)
                                                         : translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                                relationshipEntry, ModifiedPropertiesBehavior.AllModified);
                            var endResult   = relationshipResult.GetMemberValue(endMember);
                            var keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                            result = endResult.GetMemberValue(keyProperty);
                        }
                    }
                    else
                    {
                        // walk through the member path to find the appropriate propagator results
                        result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original;
                        for (var i = parameterBinding.MemberPath.Members.Count; i > 0;)
                        {
                            --i;
                            var member = parameterBinding.MemberPath.Members[i];
                            result = result.GetMemberValue(member);
                        }
                    }

                    // create DbParameter
                    command.SetParameterValue(result, parameterBinding, translator);
                }
                // Add rows affected parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
            }
            // Walks through all parameter bindings in the function mapping and binds the parameters to the
            // requested properties of the given state entry.
            private void BindFunctionParameters(UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageModificationFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary<AssociationEndMember, IEntityStateEntry> currentReferenceEnds, Dictionary<AssociationEndMember, IEntityStateEntry> originalReferenceEnds)
            {
                // bind all parameters
                foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    PropagatorResult result;

                    // extract value
                    if (null != parameterBinding.MemberPath.AssociationSetEnd)
                    {
                        // find the relationship entry corresponding to the navigation
                        AssociationEndMember endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember;
                        IEntityStateEntry relationshipEntry;
                        bool hasTarget = parameterBinding.IsCurrent
                            ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry)
                            : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry);
                        if (!hasTarget)
                        {
                            if (endMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
                            {
                                string entitySetName = stateEntry.Source.EntitySet.Name;
                                string associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name;
                                throw EntityUtil.Update(Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName),
                                    null,
                                    command.GetStateEntries(translator));
                            }
                            else
                            {
                                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null);
                            }
                        }
                        else
                        {
                            // get the actual value
                            PropagatorResult relationshipResult = parameterBinding.IsCurrent ?
                                translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified) :
                                translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified);
                            PropagatorResult endResult = relationshipResult.GetMemberValue(endMember);
                            EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; 
                            result = endResult.GetMemberValue(keyProperty);
                        }
                    }
                    else
                    {
                        // walk through the member path to find the appropriate propagator results
                        result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original;
                        for (int i = parameterBinding.MemberPath.Members.Count; i > 0;)
                        {
                            --i;
                            EdmMember member = parameterBinding.MemberPath.Members[i];
                            result = result.GetMemberValue(member);
                        }
                    }

                    // create DbParameter
                    command.SetParameterValue(result, parameterBinding, translator);
                }
                // Add rows affected parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
            }
示例#33
0
        private void ConfigureParameters(StorageModificationFunctionMapping modificationFunctionMapping)
        {
            foreach (var keyValue in _parameterNames)
            {
                var propertyPath  = keyValue.Key.PropertyPath;
                var parameterName = keyValue.Value.Item1;
                var originalValueParameterName = keyValue.Value.Item2;

                var parameterBindings
                    = modificationFunctionMapping
                      .ParameterBindings
                      .Where(
                          pb =>   // First, try and match scalar/complex/many-to-many binding
                          (((pb.MemberPath.AssociationSetEnd == null) ||
                            pb.MemberPath.AssociationSetEnd.ParentAssociationSet.ElementType.IsManyToMany()) &&
                           propertyPath.Equals(
                               new PropertyPath(
                                   pb.MemberPath.Members.OfType <EdmProperty>().Select(m => m.GetClrPropertyInfo()))))
                          ||
                          // Otherwise, try and match IA FK bindings
                          ((propertyPath.Count == 2) &&
                           (pb.MemberPath.AssociationSetEnd != null) &&
                           pb.MemberPath.Members.First().GetClrPropertyInfo().IsSameAs(propertyPath.Last()) &&
                           pb.MemberPath.AssociationSetEnd.ParentAssociationSet.AssociationSetEnds
                           .Select(ae => ae.CorrespondingAssociationEndMember.GetClrPropertyInfo())
                           .Where(pi => pi != null)
                           .Any(pi => pi.IsSameAs(propertyPath.First()))))
                      .ToList();

                if (parameterBindings.Count == 1)
                {
                    var parameterBinding = parameterBindings.Single();

                    if (!string.IsNullOrWhiteSpace(originalValueParameterName))
                    {
                        if (parameterBinding.IsCurrent)
                        {
                            throw Error.ModificationFunctionParameterNotFoundOriginal(
                                      propertyPath,
                                      modificationFunctionMapping.Function.FunctionName);
                        }
                    }

                    parameterBinding.Parameter.Name = parameterName;

                    _configuredParameters.Add(parameterBinding.Parameter);
                }
                else if (parameterBindings.Count == 2)
                {
                    var parameterBinding
                        = ((parameterBindings
                            .Select(pb => pb.IsCurrent)
                            .Distinct()
                            .Count() == 1) &&  // same value for both
                           parameterBindings
                           .All(pb => pb.MemberPath.AssociationSetEnd != null))
                              ? !keyValue.Key.IsRightKey
                                    ? parameterBindings.First()
                                    : parameterBindings.Last()
                              : parameterBindings.Single(pb => pb.IsCurrent);

                    parameterBinding.Parameter.Name = parameterName;

                    _configuredParameters.Add(parameterBinding.Parameter);

                    if (!string.IsNullOrWhiteSpace(originalValueParameterName))
                    {
                        parameterBinding = parameterBindings.Single(pb => !pb.IsCurrent);

                        parameterBinding.Parameter.Name = originalValueParameterName;

                        _configuredParameters.Add(parameterBinding.Parameter);
                    }
                }
                else
                {
                    throw Error.ModificationFunctionParameterNotFound(
                              propertyPath,
                              modificationFunctionMapping.Function.FunctionName);
                }
            }

            var unconfiguredParameters
                = modificationFunctionMapping
                  .Function
                  .Parameters
                  .Except(_configuredParameters);

            foreach (var parameter in unconfiguredParameters)
            {
                parameter.Name
                    = modificationFunctionMapping
                      .Function
                      .Parameters
                      .Except(new[] { parameter })
                      .UniquifyName(parameter.Name);
            }
        }
        private StorageModificationFunctionMapping GenerateFunctionMapping(
            ModificationOperator modificationOperator,
            EntitySetBase entitySetBase,
            EntityTypeBase entityTypeBase,
            DbDatabaseMapping databaseMapping,
            IEnumerable <EdmProperty> parameterProperties,
            IEnumerable <Tuple <StorageModificationFunctionMemberPath, EdmProperty> > iaFkProperties,
            IList <ColumnMappingBuilder> columnMappings,
            IEnumerable <EdmProperty> resultProperties = null,
            string functionNamePrefix = null)
        {
            DebugCheck.NotNull(entitySetBase);
            DebugCheck.NotNull(entityTypeBase);
            DebugCheck.NotNull(databaseMapping);
            DebugCheck.NotNull(parameterProperties);
            DebugCheck.NotNull(iaFkProperties);
            DebugCheck.NotNull(columnMappings);

            var useOriginalValues = modificationOperator == ModificationOperator.Delete;

            var parameterMappingGenerator
                = new FunctionParameterMappingGenerator(_providerManifest);

            var parameterBindings
                = parameterMappingGenerator
                  .Generate(
                      modificationOperator,
                      parameterProperties,
                      columnMappings,
                      new List <EdmProperty>(),
                      useOriginalValues)
                  .Concat(
                      parameterMappingGenerator
                      .Generate(iaFkProperties, useOriginalValues))
                  .ToList();

            var parameters
                = parameterBindings.Select(b => b.Parameter).ToList();

            UniquifyParameterNames(parameters);

            var functionPayload
                = new EdmFunctionPayload
                {
                ReturnParameters = new FunctionParameter[0],
                Parameters       = parameters.ToArray(),
                IsComposable     = false
                };

            var function
                = databaseMapping.Database
                  .AddFunction(
                      (functionNamePrefix ?? entityTypeBase.Name) + "_" + modificationOperator.ToString(),
                      functionPayload);

            var functionMapping
                = new StorageModificationFunctionMapping(
                      entitySetBase,
                      entityTypeBase,
                      function,
                      parameterBindings,
                      null,
                      resultProperties != null
                        ? resultProperties.Select(
                          p => new StorageModificationFunctionResultBinding(
                              columnMappings.First(cm => cm.PropertyPath.SequenceEqual(new[] { p })).ColumnProperty.Name,
                              p))
                        : null);

            return(functionMapping);
        }
        private StorageModificationFunctionMapping GenerateFunctionMapping(
            ModificationOperator modificationOperator,
            EntitySetBase entitySetBase,
            EntityTypeBase entityTypeBase,
            DbDatabaseMapping databaseMapping,
            IEnumerable <EdmProperty> parameterProperties,
            IEnumerable <Tuple <StorageModificationFunctionMemberPath, EdmProperty> > iaFkProperties,
            IList <ColumnMappingBuilder> columnMappings,
            IEnumerable <EdmProperty> resultProperties = null)
        {
            DebugCheck.NotNull(entitySetBase);
            DebugCheck.NotNull(entityTypeBase);
            DebugCheck.NotNull(databaseMapping);
            DebugCheck.NotNull(parameterProperties);
            DebugCheck.NotNull(iaFkProperties);
            DebugCheck.NotNull(columnMappings);

            var useOriginalValues = modificationOperator == ModificationOperator.Delete;

            var parameterMappingGenerator
                = new FunctionParameterMappingGenerator(_providerManifest);

            var parameterBindings
                = parameterMappingGenerator
                  .Generate(
                      modificationOperator,
                      parameterProperties,
                      columnMappings,
                      new List <EdmProperty>(),
                      useOriginalValues)
                  .Concat(
                      parameterMappingGenerator
                      .Generate(iaFkProperties, useOriginalValues))
                  .ToList();

            FunctionParameter rowsAffectedParameter = null;

            var parameters
                = parameterBindings.Select(b => b.Parameter).ToList();

            if (parameterBindings
                .Any(
                    pb => !pb.IsCurrent &&
                    pb.MemberPath.AssociationSetEnd == null &&
                    ((EdmProperty)pb.MemberPath.Members.Last()).ConcurrencyMode == ConcurrencyMode.Fixed))
            {
                rowsAffectedParameter
                    = new FunctionParameter(
                          "RowsAffected",
                          _providerManifest.GetStoreType(
                              TypeUsage.CreateDefaultTypeUsage(
                                  PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32))),
                          ParameterMode.Out);

                parameters.Add(rowsAffectedParameter);
            }

            UniquifyParameterNames(parameters);

            var functionPayload
                = new EdmFunctionPayload
                {
                ReturnParameters = new FunctionParameter[0],
                Parameters       = parameters.ToArray(),
                IsComposable     = false
                };

            var function
                = databaseMapping.Database
                  .AddFunction(
                      entityTypeBase.Name + "_" + modificationOperator.ToString(),
                      functionPayload);

            var functionMapping
                = new StorageModificationFunctionMapping(
                      entitySetBase,
                      entityTypeBase,
                      function,
                      parameterBindings,
                      rowsAffectedParameter,
                      resultProperties != null
                        ? resultProperties.Select(
                          p => new StorageModificationFunctionResultBinding(
                              columnMappings.First(cm => cm.PropertyPath.SequenceEqual(new[] { p })).ColumnProperty.Name,
                              p))
                        : null);

            return(functionMapping);
        }