private PropagatorResult CreateSimpleResult( IEntityStateEntry stateEntry, IExtendedDataRecord record, ExtractorMetadata.MemberInformation memberInformation, int identifier, bool isModified, int recordOrdinal, object value) { CurrentValueRecord record1 = record as CurrentValueRecord; PropagatorFlags flags = memberInformation.Flags; if (!isModified) { flags |= PropagatorFlags.Preserve; } if (-1 != identifier) { PropagatorResult owner = !memberInformation.IsServerGenerated && !memberInformation.IsForeignKeyMember || record1 == null?PropagatorResult.CreateKeyValue(flags, value, stateEntry, identifier) : PropagatorResult.CreateServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal); this.m_translator.KeyManager.RegisterIdentifierOwner(owner); return(owner); } if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) && record1 != null) { return(PropagatorResult.CreateServerGenSimpleValue(flags, value, record1, recordOrdinal)); } return(PropagatorResult.CreateSimpleValue(flags, value)); }
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.ExecuteNonQueryAsync(It.IsAny <CancellationToken>())).Returns(Task.FromResult(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.ExecuteAsync(identifierValues, generatedValues, CancellationToken.None).Result; Assert.Equal(rowsAffected, rowsAffectedResult); Assert.Equal(1, timesCommandTimeoutCalled); Assert.Equal(1, timesSetInputIdentifiers); Assert.Equal(0, generatedValues.Count); }
// <summary> // Construct a new placeholder with the shape of the given placeholder. Key values are // injected into the resulting place holder and default values are substituted with // either propagator constants or progagator nulls depending on the mode established // by the <paramref name="mode" /> flag. // </summary> // <remarks> // The key is essentially an array of values. The key map indicates that for a particular // placeholder an expression (keyMap.Keys) corresponds to some ordinal in the key array. // </remarks> // <param name="placeholder"> Placeholder to clone </param> // <param name="key"> Key to substitute </param> // <param name="placeholderKey"> Key elements in the placeholder (ordinally aligned with 'key') </param> // <param name="mode"> Mode of operation. </param> // <returns> Cloned placeholder with key values </returns> internal static PropagatorResult Populate( PropagatorResult placeholder, CompositeKey key, CompositeKey placeholderKey, PopulateMode mode) { DebugCheck.NotNull(placeholder); DebugCheck.NotNull(key); DebugCheck.NotNull(placeholderKey); // Figure out which flags to apply to generated elements. var isNull = mode == PopulateMode.NullModified || mode == PopulateMode.NullPreserve; var preserve = mode == PopulateMode.NullPreserve || mode == PopulateMode.Unknown; var flags = PropagatorFlags.NoFlags; if (!isNull) { flags |= PropagatorFlags.Unknown; } // only null values are known if (preserve) { flags |= PropagatorFlags.Preserve; } var result = placeholder.Replace( node => { // See if this is a key element var keyIndex = -1; for (var i = 0; i < placeholderKey.KeyComponents.Length; i++) { if (placeholderKey.KeyComponents[i] == node) { keyIndex = i; break; } } if (keyIndex != -1) { // Key value. return(key.KeyComponents[keyIndex]); } else { // for simple entries, just return using the markup context for this // populator var value = isNull ? null : node.GetSimpleValue(); return(PropagatorResult.CreateSimpleValue(flags, value)); } }); return(result); }
public void Propagates_server_gen_values_and_returns_entities_affected() { var updateTranslatorMock = new Mock <UpdateTranslator> { CallBase = true }; var serverGenValuesPropagatedCount = 0; var generatedValue = new object(); var mockPropagatorResult = new Mock <PropagatorResult> { CallBase = true }; mockPropagatorResult.Setup(m => m.SetServerGenValue(It.IsAny <object>())) .Callback <object>( o => { serverGenValuesPropagatedCount++; Assert.Same(generatedValue, o); }); var updateCommandMock = new Mock <UpdateCommand>( updateTranslatorMock.Object, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0)); updateCommandMock.Setup( m => m.Execute( It.IsAny <Dictionary <int, object> >(), It.IsAny <List <KeyValuePair <PropagatorResult, object> > >(), It.IsAny <IDbCommandInterceptor>())) .Returns( (Dictionary <int, object> identifierValues, List <KeyValuePair <PropagatorResult, object> > generatedValues, IDbCommandInterceptor interceptor) => { generatedValues.Add( new KeyValuePair <PropagatorResult, object>(mockPropagatorResult.Object, generatedValue)); return(1); }); updateTranslatorMock.Protected().Setup <IEnumerable <UpdateCommand> >("ProduceCommands").Returns( new[] { updateCommandMock.Object }); var entitiesAffected = updateTranslatorMock.Object.Update(); Assert.Equal(0, entitiesAffected); Assert.Equal(1, serverGenValuesPropagatedCount); }
private PropagatorResult CreateSimpleResult( IEntityStateEntry stateEntry, IExtendedDataRecord record, MemberInformation memberInformation, int identifier, bool isModified, int recordOrdinal, object value) { var updatableRecord = record as CurrentValueRecord; // construct flags for the value, which is needed for complex type and simple members var flags = memberInformation.Flags; if (!isModified) { flags |= PropagatorFlags.Preserve; } if (PropagatorResult.NullIdentifier != identifier) { // construct a key member PropagatorResult result; if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) && null != updatableRecord) { result = PropagatorResult.CreateServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal); } else { result = PropagatorResult.CreateKeyValue(flags, value, stateEntry, identifier); } // we register the entity as the "owner" of an identity so that back-propagation can succeed // (keys can only be back-propagated to entities, not association ends). It also allows us // to walk to the entity state entry in case of exceptions, since the state entry propagated // through the stack may be eliminated in a project above a join. m_translator.KeyManager.RegisterIdentifierOwner(result); return(result); } else { if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) && null != updatableRecord) { // note: we only produce a server gen result when return(PropagatorResult.CreateServerGenSimpleValue(flags, value, updatableRecord, recordOrdinal)); } else { return(PropagatorResult.CreateSimpleValue(flags, value)); } } }
// Find "sanctioned" default value internal static void GetPropagatorResultForPrimitiveType(PrimitiveType primitiveType, out PropagatorResult result) { object value; if (!TryGetDefaultValue(primitiveType, out value)) { // If none exists, default to lowest common denominator for constants value = default(byte); } // Return a new constant expression flagged as unknown since the value is only there for // show. (Not entirely for show, because null constraints may require a value for a record, // whether that record is a placeholder or not). result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value); }
public void Returns_rows_affected_when_there_is_no_reader() { var timeout = 43; var mockUpdateTranslator = new Mock <UpdateTranslator> { CallBase = true }; mockUpdateTranslator.Setup(m => m.CommandTimeout).Returns(timeout); var entityConnection = new Mock <EntityConnection>().Object; mockUpdateTranslator.Setup(m => m.Connection).Returns(entityConnection); var mockDbModificationCommandTree = new Mock <DbModificationCommandTree>(); var mockDynamicUpdateCommand = new Mock <DynamicUpdateCommand>( new Mock <TableChangeProcessor>().Object, mockUpdateTranslator.Object, ModificationOperator.Delete, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), mockDbModificationCommandTree.Object, /*outputIdentifiers*/ null) { CallBase = true }; var mockDbCommand = new Mock <DbCommand>(); var timesCommandTimeoutCalled = 0; mockDbCommand.SetupSet(m => m.CommandTimeout = It.IsAny <int>()).Callback( (int value) => { timesCommandTimeoutCalled++; Assert.Equal(timeout, value); }); var rowsAffected = 36; mockDbCommand.Setup(m => m.ExecuteNonQuery()).Returns(rowsAffected); var identifierValues = new Dictionary <int, object>(); mockDynamicUpdateCommand.Protected().Setup <DbCommand>("CreateCommand", identifierValues).Returns(mockDbCommand.Object); var generatedValues = new List <KeyValuePair <PropagatorResult, object> >(); var rowsAffectedResult = mockDynamicUpdateCommand.Object.Execute(identifierValues, generatedValues); Assert.Equal(rowsAffected, rowsAffectedResult); Assert.Equal(1, timesCommandTimeoutCalled); Assert.Equal(0, generatedValues.Count); }
public void Wraps_exceptions() { var updateTranslatorMock = new Mock <UpdateTranslator> { CallBase = true }; var dbException = new Mock <DbException>("Exception message").Object; var updateCommandMock = new Mock <UpdateCommand>( updateTranslatorMock.Object, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0)); updateCommandMock.Setup( m => m.ExecuteAsync( It.IsAny <Dictionary <int, object> >(), It.IsAny <List <KeyValuePair <PropagatorResult, object> > >(), It.IsAny <CancellationToken>())) .Returns( (Dictionary <int, object> identifierValues, List <KeyValuePair <PropagatorResult, object> > generatedValues, CancellationToken cancellationToken) => { throw dbException; }); var objectStateManager = new Mock <ObjectStateManager> { CallBase = true }.Object; var objectStateEntryMock = new Mock <ObjectStateEntry>(objectStateManager, /*entitySet:*/ null, EntityState.Unchanged); updateCommandMock.Setup(m => m.GetStateEntries(It.IsAny <UpdateTranslator>())) .Returns(new[] { objectStateEntryMock.Object }); new List <KeyValuePair <PropagatorResult, object> >(); updateTranslatorMock.Protected().Setup <IEnumerable <UpdateCommand> >("ProduceCommands").Returns( new[] { updateCommandMock.Object }); var exception = Assert.Throws <AggregateException>(() => updateTranslatorMock.Object.UpdateAsync(CancellationToken.None).Result); Assert.IsType <UpdateException>(exception.InnerException); Assert.Equal(Strings.Update_GeneralExecutionException, exception.InnerException.Message); Assert.Same(dbException, exception.InnerException.InnerException); Assert.Same(objectStateEntryMock.Object, ((UpdateException)exception.InnerException).StateEntries.Single()); }
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); }
public void Execute_calls_interceptor_when_there_is_no_reader_and_cancels_execution() { var mockUpdateTranslator = new Mock <UpdateTranslator>(MockBehavior.Strict); mockUpdateTranslator.Setup(m => m.CommandTimeout).Returns(43); var entityConnection = new Mock <EntityConnection>().Object; mockUpdateTranslator.Setup(m => m.Connection).Returns(entityConnection); var mockDbModificationCommandTree = new Mock <DbModificationCommandTree>(); var mockDynamicUpdateCommand = new Mock <DynamicUpdateCommand>( new Mock <TableChangeProcessor>().Object, mockUpdateTranslator.Object, ModificationOperator.Delete, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), mockDbModificationCommandTree.Object, /*outputIdentifiers*/ null) { CallBase = true }; var mockDbCommand = new Mock <DbCommand>(); var identifierValues = new Dictionary <int, object>(); mockDynamicUpdateCommand.Protected().Setup <DbCommand>("CreateCommand", identifierValues).Returns(mockDbCommand.Object); var generatedValues = new List <KeyValuePair <PropagatorResult, object> >(); var mockCommandInterceptor = new Mock <IDbCommandInterceptor>(); var rowsAffectedResult = mockDynamicUpdateCommand.Object.Execute( identifierValues, generatedValues, mockCommandInterceptor.Object); Assert.Equal(1, rowsAffectedResult); mockCommandInterceptor.Verify(i => i.Intercept(mockDbCommand.Object)); mockDbCommand.Verify(m => m.ExecuteNonQuery(), Times.Never()); }
// 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_is_a_reader() { 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 memberName = "property"; var edmProperty = new EdmProperty(memberName, TypeUsage.Create(mockPrimitiveType.Object)); var entityType = new EntityType("", "", DataSpace.CSpace, Enumerable.Empty <string>(), new[] { edmProperty }); entityType.SetReadOnly(); var mockUpdateTranslator = new Mock <UpdateTranslator>(MockBehavior.Strict); mockUpdateTranslator.Setup(m => m.CommandTimeout).Returns(() => null); var entityConnection = new Mock <EntityConnection>().Object; mockUpdateTranslator.Setup(m => m.Connection).Returns(entityConnection); var mockDbModificationCommandTree = new Mock <DbModificationCommandTree>(); mockDbModificationCommandTree.SetupGet(m => m.HasReader).Returns(true); var mockDynamicUpdateCommand = new Mock <DynamicUpdateCommand>( new Mock <TableChangeProcessor>().Object, mockUpdateTranslator.Object, ModificationOperator.Delete, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), PropagatorResult.CreateStructuralValue( new[] { PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0) }, entityType, isModified: false), mockDbModificationCommandTree.Object, /*outputIdentifiers*/ null) { CallBase = true }; var mockDbCommand = new Mock <DbCommand>(); var dbValue = 66; var mockDbDataReader = new Mock <DbDataReader>(); mockDbDataReader.Setup(m => m.GetFieldValueAsync <object>(It.IsAny <int>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult <object>(dbValue)); var rowsToRead = 2; mockDbDataReader.Setup(m => m.ReadAsync(It.IsAny <CancellationToken>())).Returns( () => { rowsToRead--; return(Task.FromResult(rowsToRead > 0)); }); mockDbDataReader.Setup(m => m.FieldCount).Returns(1); mockDbDataReader.Setup(m => m.GetName(0)).Returns(memberName); mockDbDataReader.Setup(m => m.NextResultAsync(It.IsAny <CancellationToken>())).Returns(Task.FromResult(false)); mockDbCommand.Protected() .Setup <Task <DbDataReader> >("ExecuteDbDataReaderAsync", CommandBehavior.SequentialAccess, It.IsAny <CancellationToken>()) .Returns(Task.FromResult(mockDbDataReader.Object)); var identifierValues = new Dictionary <int, object>(); mockDynamicUpdateCommand.Protected().Setup <DbCommand>("CreateCommand", identifierValues).Returns(mockDbCommand.Object); var generatedValues = new List <KeyValuePair <PropagatorResult, object> >(); var rowsAffectedResult = mockDynamicUpdateCommand.Object.ExecuteAsync(identifierValues, generatedValues, CancellationToken.None).Result; Assert.Equal(1, rowsAffectedResult); Assert.Equal(1, generatedValues.Count); Assert.Equal(dbValue, generatedValues[0].Value); Assert.Equal(0, generatedValues[0].Key.GetSimpleValue()); }
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); }