// <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(
     ModificationFunctionMapping 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);
 }
Ejemplo n.º 2
0
 private DbModificationCommandTree ConvertInternal(
     DbDeleteCommandTree commandTree)
 {
     this._currentFunctionMapping = this._entityTypeModificationFunctionMapping != null ? this._entityTypeModificationFunctionMapping.DeleteFunctionMapping : this._associationSetModificationFunctionMapping.DeleteFunctionMapping;
     return((DbModificationCommandTree) new DbDeleteCommandTree(commandTree.MetadataWorkspace, commandTree.DataSpace, commandTree.Target, commandTree.Predicate.Accept <DbExpression>((DbExpressionVisitor <DbExpression>) this)));
 }
        private void ConfigureParameters(ModificationFunctionMapping modificationStoredProcedureMapping)
        {
            foreach (var keyValue in _parameterNames)
            {
                var propertyPath  = keyValue.Key.PropertyPath;
                var parameterName = keyValue.Value.Item1;
                var originalValueParameterName = keyValue.Value.Item2;

                var parameterBindings
                    = modificationStoredProcedureMapping
                      .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,
                                      modificationStoredProcedureMapping.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,
                              modificationStoredProcedureMapping.Function.FunctionName);
                }
            }

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

            foreach (var parameter in unconfiguredParameters)
            {
                parameter.Name
                    = modificationStoredProcedureMapping
                      .Function
                      .Parameters
                      .Except(new[] { parameter })
                      .UniquifyName(parameter.Name);
            }
        }
            // 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, ModificationFunctionMapping 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);
            }
        private ModificationFunctionMapping GenerateFunctionMapping(
            ModificationOperator modificationOperator,
            EntitySetBase entitySetBase,
            EntityTypeBase entityTypeBase,
            DbDatabaseMapping databaseMapping,
            IEnumerable <EdmProperty> parameterProperties,
            IEnumerable <Tuple <ModificationFunctionMemberPath, 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 == ModificationOperator.Insert &&
                      IsTableSplitDependent(entityTypeBase, databaseMapping)
                                ? ModificationOperator.Update
                                : 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 ModificationFunctionMapping(
                      entitySetBase,
                      entityTypeBase,
                      function,
                      parameterBindings,
                      null,
                      resultProperties != null
                        ? resultProperties.Select(
                          p => new ModificationFunctionResultBinding(
                              columnMappings.First(cm => cm.PropertyPath.SequenceEqual(new[] { p })).ColumnProperty.Name,
                              p))
                        : null);

            return(functionMapping);
        }
Ejemplo n.º 6
0
        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 ModificationFunctionMapping(
                      associationSet,
                      associationSet.ElementType,
                      new EdmFunction("F", "N", DataSpace.SSpace, new EdmFunctionPayload()),
                      new[]
            {
                new ModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new ModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    new EdmProperty("K"),
                    associationEndMember1
                },
                        associationSet),
                    true),
                new ModificationFunctionParameterBinding(
                    new FunctionParameter(
                        "P",
                        TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)),
                        ParameterMode.In),
                    new ModificationFunctionMemberPath(
                        new EdmMember[]
                {
                    new EdmProperty("K"),
                    associationEndMember2
                },
                        associationSet),
                    false)
            },
                      null,
                      null);

            var associationSetMapping
                = new AssociationSetMapping(
                      associationSet,
                      entitySet)
                {
                SourceEndMapping
                    = new EndPropertyMapping
                    {
                    AssociationEnd = associationEndMember1
                    },
                TargetEndMapping
                    = new EndPropertyMapping
                    {
                    AssociationEnd = associationEndMember2
                    },
                ModificationFunctionMapping = new AssociationSetModificationFunctionMapping(
                    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());
        }
Ejemplo n.º 7
0
            // 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, ModificationFunctionMapping 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);
            }