public void Returns_rows_affected_when_there_are_no_result_columns() { var stateEntries = new ReadOnlyCollection <IEntityStateEntry>(new List <IEntityStateEntry>()); var stateEntry = new ExtractedStateEntry( EntityState.Unchanged, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), new Mock <IEntityStateEntry>().Object); var timeout = 43; var updateTranslatorMock = new Mock <UpdateTranslator>(); updateTranslatorMock.Setup(m => m.CommandTimeout).Returns(timeout); var entityConnection = new Mock <EntityConnection>().Object; updateTranslatorMock.Setup(m => m.Connection).Returns(entityConnection); updateTranslatorMock.Setup(m => m.InterceptionContext).Returns(new DbInterceptionContext()); var dbCommandMock = new Mock <DbCommand>(); var mockFunctionUpdateCommand = new Mock <FunctionUpdateCommand>( updateTranslatorMock.Object, stateEntries, stateEntry, dbCommandMock.Object) { CallBase = true }; var timesCommandTimeoutCalled = 0; dbCommandMock.SetupSet(m => m.CommandTimeout = It.IsAny <int>()).Callback( (int value) => { timesCommandTimeoutCalled++; Assert.Equal(timeout, value); }); var rowsAffected = 36; dbCommandMock.Setup(m => m.ExecuteNonQuery()).Returns(rowsAffected); var timesSetInputIdentifiers = 0; var identifierValues = new Dictionary <int, object>(); mockFunctionUpdateCommand.Setup(m => m.SetInputIdentifiers(It.IsAny <Dictionary <int, object> >())) .Callback <Dictionary <int, object> >( identifierValuesPassed => { timesSetInputIdentifiers++; Assert.Same(identifierValues, identifierValuesPassed); }); var generatedValues = new List <KeyValuePair <PropagatorResult, object> >(); var rowsAffectedResult = mockFunctionUpdateCommand.Object.Execute(identifierValues, generatedValues); Assert.Equal(rowsAffected, rowsAffectedResult); Assert.Equal(1, timesCommandTimeoutCalled); Assert.Equal(1, timesSetInputIdentifiers); Assert.Equal(0, generatedValues.Count); }
protected FunctionUpdateCommand( UpdateTranslator translator, ReadOnlyCollection<IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry, DbCommand dbCommand) : base(translator, stateEntry.Original, stateEntry.Current) { // populate the main state entry for error reporting _stateEntries = stateEntries; _dbCommand = dbCommand; }
/// <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); }
/// <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); }
protected FunctionUpdateCommand( UpdateTranslator translator, ReadOnlyCollection <System.Data.Entity.Core.IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry, DbCommand dbCommand) : base(translator, stateEntry.Original, stateEntry.Current) { this._stateEntries = stateEntries; this._dbCommand = (DbCommand) new InterceptableDbCommand(dbCommand, translator.InterceptionContext, (DbDispatchers)null); }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { if (null == m_mapping) { return(null); } var 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 var functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping; var command = new FunctionUpdateCommand( functionMapping, translator, new ReadOnlyCollection <IEntityStateEntry>(new[] { stateEntry.Source }.ToList()), stateEntry); // extract the relationship values from the state entry PropagatorResult recordResult; if (isInsert) { recordResult = stateEntry.Current; } else { recordResult = stateEntry.Original; } // bind parameters foreach (var 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"); var keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; var endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1]; // get the end member var endResult = recordResult.GetMemberValue(endMember); var keyResult = endResult.GetMemberValue(keyProperty); command.SetParameterValue(keyResult, parameterBinding, translator); } // add rows affected output parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); return(command); }
/// <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); }
protected FunctionUpdateCommand( UpdateTranslator translator, ReadOnlyCollection <IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry, DbCommand dbCommand) : base(translator, stateEntry.Original, stateEntry.Current) { // populate the main state entry for error reporting _stateEntries = stateEntries; _dbCommand = new InterceptableDbCommand(dbCommand, translator.InterceptionContext); }
public void Returns_rows_affected_when_there_are_no_result_columns() { var stateEntries = new ReadOnlyCollection<IEntityStateEntry>(new List<IEntityStateEntry>()); var stateEntry = new ExtractedStateEntry( EntityState.Unchanged, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), new Mock<IEntityStateEntry>().Object); var timeout = 43; var updateTranslatorMock = new Mock<UpdateTranslator>(); updateTranslatorMock.Setup(m => m.CommandTimeout).Returns(timeout); var entityConnection = new Mock<EntityConnection>().Object; updateTranslatorMock.Setup(m => m.Connection).Returns(entityConnection); updateTranslatorMock.Setup(m => m.InterceptionContext).Returns(new DbInterceptionContext()); var dbCommandMock = new Mock<DbCommand>(); var mockFunctionUpdateCommand = new Mock<FunctionUpdateCommand>( updateTranslatorMock.Object, stateEntries, stateEntry, dbCommandMock.Object) { CallBase = true }; var timesCommandTimeoutCalled = 0; dbCommandMock.SetupSet(m => m.CommandTimeout = It.IsAny<int>()).Callback( (int value) => { timesCommandTimeoutCalled++; Assert.Equal(timeout, value); }); var rowsAffected = 36; dbCommandMock.Setup(m => m.ExecuteNonQuery()).Returns(rowsAffected); var timesSetInputIdentifiers = 0; var identifierValues = new Dictionary<int, object>(); mockFunctionUpdateCommand.Setup(m => m.SetInputIdentifiers(It.IsAny<Dictionary<int, object>>())) .Callback<Dictionary<int, object>>( identifierValuesPassed => { timesSetInputIdentifiers++; Assert.Same(identifierValues, identifierValuesPassed); }); var generatedValues = new List<KeyValuePair<PropagatorResult, object>>(); var rowsAffectedResult = mockFunctionUpdateCommand.Object.Execute(identifierValues, generatedValues); Assert.Equal(rowsAffected, rowsAffectedResult); Assert.Equal(1, timesCommandTimeoutCalled); Assert.Equal(1, timesSetInputIdentifiers); Assert.Equal(0, generatedValues.Count); }
private Tuple <EntityTypeModificationFunctionMapping, ModificationFunctionMapping> GetFunctionMapping( ExtractedStateEntry stateEntry) { // choose mapping based on type and operation ModificationFunctionMapping functionMapping; EntityType entityType; if (null != stateEntry.Current) { entityType = (EntityType)stateEntry.Current.StructuralType; } else { entityType = (EntityType)stateEntry.Original.StructuralType; } var typeMapping = m_typeMappings[entityType]; switch (stateEntry.State) { case EntityState.Added: functionMapping = typeMapping.InsertFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Insert", stateEntry.Source, "EntityType", entityType.Name); break; case EntityState.Deleted: functionMapping = typeMapping.DeleteFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Delete", stateEntry.Source, "EntityType", entityType.Name); break; case EntityState.Unchanged: case EntityState.Modified: functionMapping = typeMapping.UpdateFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Update", stateEntry.Source, "EntityType", entityType.Name); break; default: functionMapping = null; Debug.Fail("unexpected state"); break; } return(Tuple.Create(typeMapping, functionMapping)); }
public void OperationCanceledException_thrown_if_task_is_cancelled() { var mockTranslator = new Mock <UpdateTranslator>(); mockTranslator.Setup(t => t.InterceptionContext).Returns(new DbInterceptionContext()); var stateEntry = new ExtractedStateEntry((EntityState)(-1), null, null, null); var functionUpdateCommand = new Mock <FunctionUpdateCommand>(mockTranslator.Object, new List <IEntityStateEntry>().AsReadOnly(), stateEntry, new Mock <DbCommand>().Object) { CallBase = true }.Object; Assert.Throws <OperationCanceledException>( () => functionUpdateCommand.ExecuteAsync(null, null, new CancellationToken(canceled: true)) .GetAwaiter().GetResult()); }
private static void BindFunctionParameters( UpdateTranslator translator, ExtractedStateEntry stateEntry, ModificationFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary <AssociationEndMember, IEntityStateEntry> currentReferenceEnds, Dictionary <AssociationEndMember, IEntityStateEntry> originalReferenceEnds) { foreach (ModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings) { PropagatorResult result; if (parameterBinding.MemberPath.AssociationSetEnd != null) { AssociationEndMember associationEndMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember; IEntityStateEntry stateEntry1; if (!(parameterBinding.IsCurrent ? currentReferenceEnds.TryGetValue(associationEndMember, out stateEntry1) : originalReferenceEnds.TryGetValue(associationEndMember, out stateEntry1))) { if (associationEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) { throw new UpdateException(Strings.Update_MissingRequiredRelationshipValue((object)stateEntry.Source.EntitySet.Name, (object)parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name), (Exception)null, command.GetStateEntries(translator).Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>()); } result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, (object)null); } else { result = (parameterBinding.IsCurrent ? translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(stateEntry1, ModifiedPropertiesBehavior.AllModified) : translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(stateEntry1, ModifiedPropertiesBehavior.AllModified)).GetMemberValue((EdmMember)associationEndMember).GetMemberValue(parameterBinding.MemberPath.Members[0]); } } else { result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original; int count = parameterBinding.MemberPath.Members.Count; while (count > 0) { --count; EdmMember member = parameterBinding.MemberPath.Members[count]; result = result.GetMemberValue(member); } } command.SetParameterValue(result, parameterBinding, translator); } command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { ModificationFunctionMapping functionMapping = this.GetFunctionMapping(stateEntry).Item2; EntityKey entityKey = stateEntry.Source.EntityKey; HashSet <IEntityStateEntry> entityStateEntrySet = new HashSet <IEntityStateEntry>() { stateEntry.Source }; IEnumerable <Tuple <AssociationEndMember, IEntityStateEntry> > tuples = functionMapping.CollocatedAssociationSetEnds.Join <AssociationSetEnd, IEntityStateEntry, StructuralType, Tuple <AssociationEndMember, IEntityStateEntry> >(translator.GetRelationships(entityKey), (Func <AssociationSetEnd, StructuralType>)(end => end.CorrespondingAssociationEndMember.DeclaringType), (Func <IEntityStateEntry, StructuralType>)(candidateEntry => (StructuralType)candidateEntry.EntitySet.ElementType), (Func <AssociationSetEnd, IEntityStateEntry, Tuple <AssociationEndMember, IEntityStateEntry> >)((end, candidateEntry) => Tuple.Create <AssociationEndMember, IEntityStateEntry>(end.CorrespondingAssociationEndMember, candidateEntry))); Dictionary <AssociationEndMember, IEntityStateEntry> dictionary1 = new Dictionary <AssociationEndMember, IEntityStateEntry>(); Dictionary <AssociationEndMember, IEntityStateEntry> dictionary2 = new Dictionary <AssociationEndMember, IEntityStateEntry>(); foreach (Tuple <AssociationEndMember, IEntityStateEntry> tuple in tuples) { ModificationFunctionMappingTranslator.EntitySetTranslator.ProcessReferenceCandidate(entityKey, entityStateEntrySet, dictionary1, dictionary2, tuple.Item1, tuple.Item2); } FunctionUpdateCommand command; if (entityStateEntrySet.All <IEntityStateEntry>((Func <IEntityStateEntry, bool>)(e => e.State == EntityState.Unchanged))) { command = (FunctionUpdateCommand)null; } else { command = new FunctionUpdateCommand(functionMapping, translator, new ReadOnlyCollection <IEntityStateEntry>((IList <IEntityStateEntry>)entityStateEntrySet.ToList <IEntityStateEntry>()), stateEntry); ModificationFunctionMappingTranslator.EntitySetTranslator.BindFunctionParameters(translator, stateEntry, functionMapping, command, dictionary1, dictionary2); if (functionMapping.ResultBindings != null) { foreach (ModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings) { PropagatorResult memberValue = stateEntry.Current.GetMemberValue((EdmMember)resultBinding.Property); command.AddResultColumn(translator, resultBinding.ColumnName, memberValue); } } } return(command); }
public void Returns_rows_affected_when_there_are_result_columns() { var mockPrimitiveType = new Mock <PrimitiveType>(); mockPrimitiveType.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.PrimitiveType); mockPrimitiveType.Setup(m => m.PrimitiveTypeKind).Returns(PrimitiveTypeKind.Int32); mockPrimitiveType.Setup(m => m.DataSpace).Returns(DataSpace.CSpace); var edmProperty = new EdmProperty("property", TypeUsage.Create(mockPrimitiveType.Object)); var entityType = new EntityType("", "", DataSpace.CSpace, Enumerable.Empty <string>(), new[] { edmProperty }); entityType.SetReadOnly(); var stateEntry = new ExtractedStateEntry( EntityState.Unchanged, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateStructuralValue( new[] { PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0) }, entityType, isModified: false), new Mock <IEntityStateEntry>().Object); var updateTranslatorMock = new Mock <UpdateTranslator>(); updateTranslatorMock.Setup(m => m.CommandTimeout).Returns(() => null); var entityConnection = new Mock <EntityConnection>().Object; updateTranslatorMock.Setup(m => m.Connection).Returns(entityConnection); updateTranslatorMock.Setup(m => m.InterceptionContext).Returns(new DbInterceptionContext()); var dbCommandMock = new Mock <DbCommand>(); var stateEntries = new ReadOnlyCollection <IEntityStateEntry>(new List <IEntityStateEntry>()); var mockFunctionUpdateCommand = new Mock <FunctionUpdateCommand>( updateTranslatorMock.Object, stateEntries, stateEntry, dbCommandMock.Object) { CallBase = true }; var dbValue = 66; var dbDataReaderMock = new Mock <DbDataReader>(); dbDataReaderMock.Setup(m => m.GetValue(It.IsAny <int>())).Returns(dbValue); var rowsToRead = 2; dbDataReaderMock.Setup(m => m.Read()).Returns( () => { rowsToRead--; return(rowsToRead > 0); }); dbCommandMock.Protected().Setup <DbDataReader>("ExecuteDbDataReader", CommandBehavior.SequentialAccess).Returns( dbDataReaderMock.Object); var timesSetInputIdentifiers = 0; var identifierValues = new Dictionary <int, object>(); mockFunctionUpdateCommand.Setup(m => m.SetInputIdentifiers(It.IsAny <Dictionary <int, object> >())) .Callback <Dictionary <int, object> >( identifierValuesPassed => { timesSetInputIdentifiers++; Assert.Same(identifierValues, identifierValuesPassed); }); var generatedValues = new List <KeyValuePair <PropagatorResult, object> >(); var mockObjectStateManager = new Mock <ObjectStateManager>(); var objectStateEntryMock = new Mock <ObjectStateEntry>(mockObjectStateManager.Object, null, EntityState.Unchanged); var currentValueRecordMock = new Mock <CurrentValueRecord>(objectStateEntryMock.Object); var idColumn = new KeyValuePair <string, PropagatorResult>( "ID", PropagatorResult.CreateServerGenSimpleValue( PropagatorFlags.NoFlags, /*value:*/ 0, currentValueRecordMock.Object, recordOrdinal: 0)); mockFunctionUpdateCommand.Protected().Setup <List <KeyValuePair <string, PropagatorResult> > >("ResultColumns") .Returns((new[] { idColumn }).ToList()); var rowsAffectedResult = mockFunctionUpdateCommand.Object.Execute(identifierValues, generatedValues); Assert.Equal(1, rowsAffectedResult); Assert.Equal(1, timesSetInputIdentifiers); Assert.Equal(1, generatedValues.Count); Assert.Same(idColumn.Value, generatedValues[0].Key); Assert.Equal(dbValue, generatedValues[0].Value); }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { var mapping = GetFunctionMapping(stateEntry); var functionMapping = mapping.Item2; var 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 command = null; } else { command = new FunctionUpdateCommand(functionMapping, translator, new ReadOnlyCollection <IEntityStateEntry>(stateEntries.ToList()), stateEntry); // bind all function parameters BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds); // interpret all result bindings if (null != functionMapping.ResultBindings) { foreach (var resultBinding in functionMapping.ResultBindings) { var result = stateEntry.Current.GetMemberValue(resultBinding.Property); command.AddResultColumn(translator, resultBinding.ColumnName, result); } } } return(command); }
private Tuple<EntityTypeModificationFunctionMapping, ModificationFunctionMapping> GetFunctionMapping( ExtractedStateEntry stateEntry) { // choose mapping based on type and operation ModificationFunctionMapping functionMapping; EntityType entityType; if (null != stateEntry.Current) { entityType = (EntityType)stateEntry.Current.StructuralType; } else { entityType = (EntityType)stateEntry.Original.StructuralType; } var typeMapping = m_typeMappings[entityType]; switch (stateEntry.State) { case EntityState.Added: functionMapping = typeMapping.InsertFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Insert", stateEntry.Source, "EntityType", entityType.Name); break; case EntityState.Deleted: functionMapping = typeMapping.DeleteFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Delete", stateEntry.Source, "EntityType", entityType.Name); break; case EntityState.Unchanged: case EntityState.Modified: functionMapping = typeMapping.UpdateFunctionMapping; EntityUtil.ValidateNecessaryModificationFunctionMapping( functionMapping, "Update", stateEntry.Source, "EntityType", entityType.Name); break; default: functionMapping = null; Debug.Fail("unexpected state"); break; } return Tuple.Create(typeMapping, functionMapping); }
// <summary> // Requires: this translator must be registered to handle the entity set // for the given state entry. // Translates the given state entry to a command. // </summary> // <param name="translator"> Parent update translator (global state for the workload) </param> // <param name="stateEntry"> State entry to translate. Must belong to the entity/association set handled by this translator </param> // <returns> Command corresponding to the given state entry </returns> internal abstract FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry);
// 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); }
// 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); }
public void Returns_rows_affected_when_there_are_result_columns() { var mockPrimitiveType = new Mock<PrimitiveType>(); mockPrimitiveType.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.PrimitiveType); mockPrimitiveType.Setup(m => m.PrimitiveTypeKind).Returns(PrimitiveTypeKind.Int32); mockPrimitiveType.Setup(m => m.DataSpace).Returns(DataSpace.CSpace); var edmProperty = new EdmProperty("property", TypeUsage.Create(mockPrimitiveType.Object)); var entityType = new EntityType("", "", DataSpace.CSpace, Enumerable.Empty<string>(), new[] { edmProperty }); entityType.SetReadOnly(); var stateEntry = new ExtractedStateEntry( EntityState.Unchanged, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateStructuralValue( new[] { PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0) }, entityType, isModified: false), new Mock<IEntityStateEntry>().Object); var updateTranslatorMock = new Mock<UpdateTranslator>(); updateTranslatorMock.Setup(m => m.CommandTimeout).Returns(() => null); var entityConnection = new Mock<EntityConnection>().Object; updateTranslatorMock.Setup(m => m.Connection).Returns(entityConnection); updateTranslatorMock.Setup(m => m.InterceptionContext).Returns(new DbInterceptionContext()); var dbCommandMock = new Mock<DbCommand>(); var stateEntries = new ReadOnlyCollection<IEntityStateEntry>(new List<IEntityStateEntry>()); var mockFunctionUpdateCommand = new Mock<FunctionUpdateCommand>( updateTranslatorMock.Object, stateEntries, stateEntry, dbCommandMock.Object) { CallBase = true }; var dbValue = 66; var dbDataReaderMock = new Mock<DbDataReader>(); dbDataReaderMock.Setup(m => m.GetValue(It.IsAny<int>())).Returns(dbValue); var rowsToRead = 2; dbDataReaderMock.Setup(m => m.Read()).Returns( () => { rowsToRead--; return rowsToRead > 0; }); dbCommandMock.Protected().Setup<DbDataReader>("ExecuteDbDataReader", CommandBehavior.SequentialAccess).Returns( dbDataReaderMock.Object); var timesSetInputIdentifiers = 0; var identifierValues = new Dictionary<int, object>(); mockFunctionUpdateCommand.Setup(m => m.SetInputIdentifiers(It.IsAny<Dictionary<int, object>>())) .Callback<Dictionary<int, object>>( identifierValuesPassed => { timesSetInputIdentifiers++; Assert.Same(identifierValues, identifierValuesPassed); }); var generatedValues = new List<KeyValuePair<PropagatorResult, object>>(); var mockObjectStateManager = new Mock<ObjectStateManager>(); var objectStateEntryMock = new Mock<ObjectStateEntry>(mockObjectStateManager.Object, null, EntityState.Unchanged); var currentValueRecordMock = new Mock<CurrentValueRecord>(objectStateEntryMock.Object); var idColumn = new KeyValuePair<string, PropagatorResult>( "ID", PropagatorResult.CreateServerGenSimpleValue( PropagatorFlags.NoFlags, /*value:*/ 0, currentValueRecordMock.Object, recordOrdinal: 0)); mockFunctionUpdateCommand.Protected().Setup<List<KeyValuePair<string, PropagatorResult>>>("ResultColumns") .Returns((new[] { idColumn }).ToList()); var rowsAffectedResult = mockFunctionUpdateCommand.Object.Execute(identifierValues, generatedValues); Assert.Equal(1, rowsAffectedResult); Assert.Equal(1, timesSetInputIdentifiers); Assert.Equal(1, generatedValues.Count); Assert.Same(idColumn.Value, generatedValues[0].Key); Assert.Equal(dbValue, generatedValues[0].Value); }
public void OperationCanceledException_thrown_if_task_is_cancelled() { var mockTranslator = new Mock<UpdateTranslator>(); mockTranslator.Setup(t => t.InterceptionContext).Returns(new DbInterceptionContext()); var stateEntry = new ExtractedStateEntry((EntityState)(-1), null, null, null); var functionUpdateCommand = new Mock<FunctionUpdateCommand>(mockTranslator.Object, new List<IEntityStateEntry>().AsReadOnly(), stateEntry, new Mock<DbCommand>().Object) { CallBase = true }.Object; Assert.Throws<OperationCanceledException>( () => functionUpdateCommand.ExecuteAsync(null, null, new CancellationToken(canceled: true)) .GetAwaiter().GetResult()); }
// <summary> // Requires: this translator must be registered to handle the entity set // for the given state entry. // Translates the given state entry to a command. // </summary> // <param name="translator"> Parent update translator (global state for the workload) </param> // <param name="stateEntry"> State entry to translate. Must belong to the entity/association set handled by this translator </param> // <returns> Command corresponding to the given state entry </returns> internal abstract FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry);
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { if (null == m_mapping) { return null; } var 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 var functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping; var command = new FunctionUpdateCommand( functionMapping, translator, new ReadOnlyCollection<IEntityStateEntry>(new[] { stateEntry.Source }.ToList()), stateEntry); // extract the relationship values from the state entry PropagatorResult recordResult; if (isInsert) { recordResult = stateEntry.Current; } else { recordResult = stateEntry.Original; } // bind parameters foreach (var 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"); var keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; var endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1]; // get the end member var endResult = recordResult.GetMemberValue(endMember); var keyResult = endResult.GetMemberValue(keyProperty); command.SetParameterValue(keyResult, parameterBinding, translator); } // add rows affected output parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); return command; }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { var mapping = GetFunctionMapping(stateEntry); var functionMapping = mapping.Item2; var 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 command = null; } else { command = new FunctionUpdateCommand(functionMapping, translator, new ReadOnlyCollection<IEntityStateEntry>(stateEntries.ToList()), stateEntry); // bind all function parameters BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds); // interpret all result bindings if (null != functionMapping.ResultBindings) { foreach (var resultBinding in functionMapping.ResultBindings) { var result = stateEntry.Current.GetMemberValue(resultBinding.Property); command.AddResultColumn(translator, resultBinding.ColumnName, result); } } } return command; }