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)); }
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); }
private void ConfigureSchema(StorageModificationFunctionMapping modificationFunctionMapping) { DebugCheck.NotNull(modificationFunctionMapping); if (!string.IsNullOrWhiteSpace(_schema)) { modificationFunctionMapping.Function.Schema = _schema; } }
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); }
/// <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); }
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); }
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()); }
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); } }
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()); }
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); }
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); }