/// <summary> /// Construct a new propagator. /// </summary> /// <param name="parent">UpdateTranslator supporting retrieval of changes for C-Space /// extents referenced in the update mapping view.</param> /// <param name="table">Table for which updates are being produced.</param> private Propagator(UpdateTranslator parent, EntitySet table) { // Initialize propagator state. EntityUtil.CheckArgumentNull(parent, "parent"); EntityUtil.CheckArgumentNull(table, "table"); m_updateTranslator = parent; m_table = table; }
// <summary> // Construct a new propagator. // </summary> // <param name="parent"> UpdateTranslator supporting retrieval of changes for C-Space extents referenced in the update mapping view. </param> // <param name="table"> Table for which updates are being produced. </param> private Propagator(UpdateTranslator parent, EntitySet table) { // Initialize propagator state. DebugCheck.NotNull(parent); DebugCheck.NotNull(table); m_updateTranslator = parent; m_table = table; }
protected UpdateCommand( UpdateTranslator translator, PropagatorResult originalValues, PropagatorResult currentValues) { this.OriginalValues = originalValues; this.CurrentValues = currentValues; this.Translator = translator; }
/// <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 string GetQueryWithParameter(Expression fieldUpdate, Expression where, object source) { StringBuilder sb = new StringBuilder(); var translator = new UpdateTranslator(ref command); sb.Append(translator.Translate(fieldUpdate, source)); sb.Append(" where ").Append(new WhereTranslator().Translate(where)); return(sb.ToString()); }
internal static ReadOnlyCollection <IEntityStateEntry> GetAllStateEntries( PropagatorResult source, UpdateTranslator translator, EntitySet sourceTable) { SourceInterpreter sourceInterpreter = new SourceInterpreter(translator, sourceTable); sourceInterpreter.RetrieveResultMarkup(source); return(new ReadOnlyCollection <IEntityStateEntry>((IList <IEntityStateEntry>)sourceInterpreter.m_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); }
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; }
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; }
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); }
// <summary> // Propagate changes from C-Space (contained in <paramref name="parent" /> to the S-Space. // </summary> // <remarks> // See Walker class for an explanation of this coding pattern. // </remarks> // <param name="parent"> Grouper supporting retrieval of changes for C-Space extents referenced in the update mapping view. </param> // <param name="table"> Table for which updates are being produced. </param> // <param name="umView"> Update mapping view to propagate. </param> // <returns> Changes in S-Space. </returns> internal static ChangeNode Propagate(UpdateTranslator parent, EntitySet table, DbQueryCommandTree umView) { // Construct a new instance of a propagator, which implements a visitor interface // for expression nodes (nodes in the update mapping view) and returns changes nodes // (seeded by C-Space extent changes returned by the grouper). DbExpressionVisitor <ChangeNode> propagator = new Propagator(parent, table); // Walk the update mapping view using the visitor pattern implemented in this class. // The update mapping view describes the S-Space table we're targeting, so the result // returned for the root of view corresponds to changes propagated to the S-Space. return(umView.Query.Accept(propagator)); }
// <summary> // Finds all markup associated with the given source. // </summary> // <param name="source"> Source expression. Must not be null. </param> // <param name="translator"> Translator containing session information. </param> // <param name="sourceTable"> Table from which the exception was thrown (must not be null). </param> // <returns> Markup. </returns> internal static ReadOnlyCollection<IEntityStateEntry> GetAllStateEntries( PropagatorResult source, UpdateTranslator translator, EntitySet sourceTable) { DebugCheck.NotNull(source); DebugCheck.NotNull(translator); DebugCheck.NotNull(sourceTable); var interpreter = new SourceInterpreter(translator, sourceTable); interpreter.RetrieveResultMarkup(source); return new ReadOnlyCollection<IEntityStateEntry>(interpreter.m_stateEntries); }
/// <summary> /// Finds all markup associated with the given source. /// </summary> /// <param name="source"> Source expression. Must not be null. </param> /// <param name="translator"> Translator containing session information. </param> /// <param name="sourceTable"> Table from which the exception was thrown (must not be null). </param> /// <returns> Markup. </returns> internal static ReadOnlyCollection <IEntityStateEntry> GetAllStateEntries( PropagatorResult source, UpdateTranslator translator, EntitySet sourceTable) { DebugCheck.NotNull(source); DebugCheck.NotNull(translator); DebugCheck.NotNull(sourceTable); var interpreter = new SourceInterpreter(translator, sourceTable); interpreter.RetrieveResultMarkup(source); return(new ReadOnlyCollection <IEntityStateEntry>(interpreter.m_stateEntries)); }
private int GetColumnOrdinal( UpdateTranslator translator, DbDataReader reader, string columnName) { try { return(reader.GetOrdinal(columnName)); } catch (IndexOutOfRangeException ex) { throw new UpdateException(Strings.Update_MissingResultColumn((object)columnName), (Exception)null, this.GetStateEntries(translator).Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>()); } }
private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName) { int columnOrdinal; try { columnOrdinal = reader.GetOrdinal(columnName); } catch (IndexOutOfRangeException) { throw new UpdateException( Strings.Update_MissingResultColumn(columnName), null, GetStateEntries(translator).Cast <ObjectStateEntry>().Distinct()); } return(columnOrdinal); }
private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName) { int columnOrdinal; try { columnOrdinal = reader.GetOrdinal(columnName); } catch (IndexOutOfRangeException) { throw EntityUtil.Update(System.Data.Entity.Strings.Update_MissingResultColumn(columnName), null, this.GetStateEntries(translator)); } return(columnOrdinal); }
internal void GetRequiredAndProducedEntities( UpdateTranslator translator, KeyToListMap <EntityKey, UpdateCommand> addedEntities, KeyToListMap <EntityKey, UpdateCommand> deletedEntities, KeyToListMap <EntityKey, UpdateCommand> addedRelationships, KeyToListMap <EntityKey, UpdateCommand> deletedRelationships) { IList <IEntityStateEntry> stateEntries = this.GetStateEntries(translator); foreach (IEntityStateEntry entityStateEntry in (IEnumerable <IEntityStateEntry>)stateEntries) { if (!entityStateEntry.IsRelationship) { if (entityStateEntry.State == EntityState.Added) { addedEntities.Add(entityStateEntry.EntityKey, this); } else if (entityStateEntry.State == EntityState.Deleted) { deletedEntities.Add(entityStateEntry.EntityKey, this); } } } if (this.OriginalValues != null) { this.AddReferencedEntities(translator, this.OriginalValues, deletedRelationships); } if (this.CurrentValues != null) { this.AddReferencedEntities(translator, this.CurrentValues, addedRelationships); } foreach (IEntityStateEntry entityStateEntry in (IEnumerable <IEntityStateEntry>)stateEntries) { if (entityStateEntry.IsRelationship) { bool flag = entityStateEntry.State == EntityState.Added; if (flag || entityStateEntry.State == EntityState.Deleted) { DbDataRecord dbDataRecord = flag ? (DbDataRecord)entityStateEntry.CurrentValues : entityStateEntry.OriginalValues; EntityKey key1 = (EntityKey)dbDataRecord[0]; EntityKey key2 = (EntityKey)dbDataRecord[1]; KeyToListMap <EntityKey, UpdateCommand> keyToListMap = flag ? addedRelationships : deletedRelationships; keyToListMap.Add(key1, this); keyToListMap.Add(key2, this); } } } }
// <summary> // Handles extent expressions (these are the terminal nodes in update mapping views). This handler // retrieves the changes from the grouper. // </summary> // <param name="node"> Extent expression node </param> public override ChangeNode Visit(DbScanExpression node) { Check.NotNull(node, "node"); // Gets modifications requested for this extent from the grouper. var extent = node.Target; var extentModifications = UpdateTranslator.GetExtentModifications(extent); if (null == extentModifications.Placeholder) { // Bootstrap placeholder (essentially a record for the extent populated with default values). extentModifications.Placeholder = ExtentPlaceholderCreator.CreatePlaceholder(extent); } return(extentModifications); }
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 ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry) { DebugCheck.NotNull(translator); DebugCheck.NotNull(stateEntry); State = stateEntry.State; Source = stateEntry; switch (stateEntry.State) { case EntityState.Deleted: Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.AllModified); Current = null; break; case EntityState.Unchanged: Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.NoneModified); Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.NoneModified); break; case EntityState.Modified: Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.SomeModified); Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.SomeModified); break; case EntityState.Added: Original = null; Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.AllModified); break; default: Debug.Assert(false, "Unexpected IEntityStateEntry.State for entity " + stateEntry.State); Original = null; Current = null; break; } }
// <summary> // Converts a record to a propagator result // </summary> // <param name="stateEntry"> state manager entry containing the record </param> // <param name="isModified"> Indicates whether the root element is modified (i.e., whether the type has changed) </param> // <param name="record"> Record to convert </param> // <param name="useCurrentValues"> Indicates whether we are retrieving current or original values. </param> // <param name="translator"> Translator for session context; registers new metadata for the record type if none exists </param> // <param name="modifiedPropertiesBehavior"> Indicates how to determine whether a property is modified. </param> // <returns> Result corresponding to the given record </returns> internal static PropagatorResult ExtractResultFromRecord( IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record, bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior) { var structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType; var metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType); var key = stateEntry.EntityKey; var nestedValues = new PropagatorResult[record.FieldCount]; for (var ordinal = 0; ordinal < nestedValues.Length; ordinal++) { nestedValues[ordinal] = metadata.RetrieveMember( stateEntry, record, useCurrentValues, key, ordinal, modifiedPropertiesBehavior); } return(PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified)); }
internal DynamicUpdateCommand( TableChangeProcessor processor, UpdateTranslator translator, ModificationOperator modificationOperator, PropagatorResult originalValues, PropagatorResult currentValues, DbModificationCommandTree tree, Dictionary<int, string> outputIdentifiers) : base(translator, originalValues, currentValues) { Contract.Requires(processor != null); Contract.Requires(translator != null); Contract.Requires(tree != null); _processor = processor; _operator = modificationOperator; _modificationCommandTree = tree; _outputIdentifiers = outputIdentifiers; // may be null (not all commands have output identifiers) // initialize identifier information (supports lateral propagation of server gen values) if (ModificationOperator.Insert == modificationOperator || ModificationOperator.Update == modificationOperator) { const int capacity = 2; // "average" number of identifiers per row _inputIdentifiers = new List<KeyValuePair<int, DbSetClause>>(capacity); foreach (var member in Helper.PairEnumerations( TypeHelpers.GetAllStructuralMembers(CurrentValues.StructuralType), CurrentValues.GetMemberValues())) { DbSetClause setter; var identifier = member.Value.Identifier; if (PropagatorResult.NullIdentifier != identifier && TryGetSetterExpression(tree, member.Key, modificationOperator, out setter)) // can find corresponding setter { foreach (var principal in translator.KeyManager.GetPrincipals(identifier)) { _inputIdentifiers.Add(new KeyValuePair<int, DbSetClause>(principal, setter)); } } } } }
internal DynamicUpdateCommand( TableChangeProcessor processor, UpdateTranslator translator, ModificationOperator modificationOperator, PropagatorResult originalValues, PropagatorResult currentValues, DbModificationCommandTree tree, Dictionary <int, string> outputIdentifiers) : base(translator, originalValues, currentValues) { DebugCheck.NotNull(processor); DebugCheck.NotNull(translator); DebugCheck.NotNull(tree); _processor = processor; _operator = modificationOperator; _modificationCommandTree = tree; _outputIdentifiers = outputIdentifiers; // may be null (not all commands have output identifiers) // initialize identifier information (supports lateral propagation of server gen values) if (ModificationOperator.Insert == modificationOperator || ModificationOperator.Update == modificationOperator) { const int capacity = 2; // "average" number of identifiers per row _inputIdentifiers = new List <KeyValuePair <int, DbSetClause> >(capacity); foreach (var member in Helper.PairEnumerations( TypeHelpers.GetAllStructuralMembers(CurrentValues.StructuralType), CurrentValues.GetMemberValues())) { DbSetClause setter; var identifier = member.Value.Identifier; if (PropagatorResult.NullIdentifier != identifier && TryGetSetterExpression(tree, member.Key, modificationOperator, out setter)) // can find corresponding setter { foreach (var principal in translator.KeyManager.GetPrincipals(identifier)) { _inputIdentifiers.Add(new KeyValuePair <int, DbSetClause>(principal, setter)); } } } } }
private void AddReferencedEntities( UpdateTranslator translator, PropagatorResult result, KeyToListMap <EntityKey, UpdateCommand> referencedEntities) { foreach (PropagatorResult memberValue in result.GetMemberValues()) { if (memberValue.IsSimple && memberValue.Identifier != -1 && PropagatorFlags.ForeignKey == (memberValue.PropagatorFlags & PropagatorFlags.ForeignKey)) { foreach (int directReference in translator.KeyManager.GetDirectReferences(memberValue.Identifier)) { PropagatorResult owner; if (translator.KeyManager.TryGetIdentifierOwner(directReference, out owner) && owner.StateEntry != null) { referencedEntities.Add(owner.StateEntry.EntityKey, this); } } } } }
private void AddReferencedEntities(UpdateTranslator translator, PropagatorResult result, KeyToListMap <EntityKey, UpdateCommand> referencedEntities) { foreach (PropagatorResult property in result.GetMemberValues()) { if (property.IsSimple && property.Identifier != PropagatorResult.NullIdentifier && (PropagatorFlags.ForeignKey == (property.PropagatorFlags & PropagatorFlags.ForeignKey))) { foreach (int principal in translator.KeyManager.GetDirectReferences(property.Identifier)) { PropagatorResult owner; if (translator.KeyManager.TryGetIdentifierOwner(principal, out owner) && null != owner.StateEntry) { Debug.Assert(!owner.StateEntry.IsRelationship, "owner must not be a relationship"); referencedEntities.Add(owner.StateEntry.EntityKey, this); } } } } }
internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry) { Debug.Assert(null != stateEntry, "stateEntry must not be null"); this.State = stateEntry.State; this.Source = stateEntry; switch (stateEntry.State) { case EntityState.Deleted: this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.AllModified); this.Current = null; break; case EntityState.Unchanged: this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.NoneModified); this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.NoneModified); break; case EntityState.Modified: this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.SomeModified); this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.SomeModified); break; case EntityState.Added: this.Original = null; this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult( stateEntry, ModifiedPropertiesBehavior.AllModified); break; default: Debug.Fail("unexpected IEntityStateEntry.State for entity " + stateEntry.State); this.Original = null; this.Current = null; break; } }
private PropagatorResult ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, bool useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior) { try { EntityUtil.CheckArgumentNull(stateEntry, "stateEntry"); IExtendedDataRecord record = useCurrentValues ? EntityUtil.CheckArgumentNull(stateEntry.CurrentValues as IExtendedDataRecord, "stateEntry.CurrentValues") : EntityUtil.CheckArgumentNull(stateEntry.OriginalValues as IExtendedDataRecord, "stateEntry.OriginalValues"); bool isModified = false; // the root of the state entry is unchanged because the type is static return(ExtractorMetadata.ExtractResultFromRecord(stateEntry, isModified, record, useCurrentValues, m_updateTranslator, modifiedPropertiesBehavior)); } catch (Exception e) { if (UpdateTranslator.RequiresContext(e)) { throw EntityUtil.Update(Strings.Update_ErrorLoadingRecord, e, stateEntry); } throw; } }
internal override IList <IEntityStateEntry> GetStateEntries( UpdateTranslator translator) { List <IEntityStateEntry> entityStateEntryList = new List <IEntityStateEntry>(2); if (this.OriginalValues != null) { foreach (IEntityStateEntry allStateEntry in SourceInterpreter.GetAllStateEntries(this.OriginalValues, translator, this.Table)) { entityStateEntryList.Add(allStateEntry); } } if (this.CurrentValues != null) { foreach (IEntityStateEntry allStateEntry in SourceInterpreter.GetAllStateEntries(this.CurrentValues, translator, this.Table)) { entityStateEntryList.Add(allStateEntry); } } return((IList <IEntityStateEntry>)entityStateEntryList); }
private T Update <T>(T noChangesResult, Func <UpdateTranslator, T> updateFunction) { if (!EntityAdapter.IsStateManagerDirty(this._context.ObjectStateManager)) { return(noChangesResult); } if (this._connection == null) { throw Error.EntityClient_NoConnectionForAdapter(); } if (this._connection.StoreProviderFactory == null || this._connection.StoreConnection == null) { throw Error.EntityClient_NoStoreConnectionForUpdate(); } if (ConnectionState.Open != this._connection.State) { throw Error.EntityClient_ClosedConnectionForUpdate(); } UpdateTranslator updateTranslator = this._updateTranslatorFactory(this); return(updateFunction(updateTranslator)); }
internal void AddResultColumn( UpdateTranslator translator, string columnName, PropagatorResult result) { if (this.ResultColumns == null) { this.ResultColumns = new List <KeyValuePair <string, PropagatorResult> >(2); } this.ResultColumns.Add(new KeyValuePair <string, PropagatorResult>(columnName, result)); int identifier = result.Identifier; if (-1 == identifier) { return; } if (translator.KeyManager.HasPrincipals(identifier)) { throw new InvalidOperationException(Strings.Update_GeneratedDependent((object)columnName)); } this.AddOutputIdentifier(columnName, identifier); }
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); }
internal override IList <IEntityStateEntry> GetStateEntries(UpdateTranslator translator) { var stateEntries = new List <IEntityStateEntry>(2); if (null != OriginalValues) { foreach (var stateEntry in SourceInterpreter.GetAllStateEntries( OriginalValues, translator, Table)) { stateEntries.Add(stateEntry); } } if (null != CurrentValues) { foreach (var stateEntry in SourceInterpreter.GetAllStateEntries( CurrentValues, translator, Table)) { stateEntries.Add(stateEntry); } } return(stateEntries); }
// Adds a result column binding from a column name (from the result set for the function) to // a propagator result (which contains the context necessary to back-propagate the result). // If the result is an identifier, binds the internal void AddResultColumn(UpdateTranslator translator, String columnName, PropagatorResult result) { const int initializeSize = 2; // expect on average less than two result columns per command if (null == ResultColumns) { ResultColumns = new List <KeyValuePair <string, PropagatorResult> >(initializeSize); } ResultColumns.Add(new KeyValuePair <string, PropagatorResult>(columnName, result)); var identifier = result.Identifier; if (PropagatorResult.NullIdentifier != identifier) { if (translator.KeyManager.HasPrincipals(identifier)) { throw new InvalidOperationException(Strings.Update_GeneratedDependent(columnName)); } // register output identifier to enable fix-up and dependency tracking AddOutputIdentifier(columnName, identifier); } }
// 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); }
// <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; }
// Adds a result column binding from a column name (from the result set for the function) to // a propagator result (which contains the context necessary to back-propagate the result). // If the result is an identifier, binds the internal void AddResultColumn(UpdateTranslator translator, String columnName, PropagatorResult result) { const int initializeSize = 2; // expect on average less than two result columns per command if (null == ResultColumns) { ResultColumns = new List<KeyValuePair<string, PropagatorResult>>(initializeSize); } ResultColumns.Add(new KeyValuePair<string, PropagatorResult>(columnName, result)); var identifier = result.Identifier; if (PropagatorResult.NullIdentifier != identifier) { if (translator.KeyManager.HasPrincipals(identifier)) { throw new InvalidOperationException(Strings.Update_GeneratedDependent(columnName)); } // register output identifier to enable fix-up and dependency tracking AddOutputIdentifier(columnName, identifier); } }
/// <summary> /// Converts a record to a propagator result /// </summary> /// <param name="stateEntry">state manager entry containing the record</param> /// <param name="isModified">Indicates whether the root element is modified (i.e., whether the type has changed)</param> /// <param name="record">Record to convert</param> /// <param name="useCurrentValues">Indicates whether we are retrieving current or original values.</param> /// <param name="translator">Translator for session context; registers new metadata for the record type if none /// exists</param> /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param> /// <returns>Result corresponding to the given record</returns> internal static PropagatorResult ExtractResultFromRecord( IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record, bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior) { var structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType; var metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType); var key = stateEntry.EntityKey; var nestedValues = new PropagatorResult[record.FieldCount]; for (var ordinal = 0; ordinal < nestedValues.Length; ordinal++) { nestedValues[ordinal] = metadata.RetrieveMember( stateEntry, record, useCurrentValues, key, ordinal, modifiedPropertiesBehavior); } return PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified); }
// Adds and register a DbParameter to the current command. internal void SetParameterValue( PropagatorResult result, StorageModificationFunctionParameterBinding parameterBinding, UpdateTranslator translator) { // retrieve DbParameter var parameter = _dbCommand.Parameters[parameterBinding.Parameter.Name]; var parameterType = parameterBinding.Parameter.TypeUsage; var parameterValue = translator.KeyManager.GetPrincipalValue(result); translator.SetParameterValue(parameter, parameterType, parameterValue); // if the parameter corresponds to an identifier (key component), remember this fact in case // it's important for dependency ordering (e.g., output the identifier before creating it) var identifier = result.Identifier; if (PropagatorResult.NullIdentifier != identifier) { const int initialSize = 2; // expect on average less than two input identifiers per command if (null == _inputIdentifiers) { _inputIdentifiers = new List<KeyValuePair<int, DbParameter>>(initialSize); } foreach (var principal in translator.KeyManager.GetPrincipals(identifier)) { _inputIdentifiers.Add(new KeyValuePair<int, DbParameter>(principal, parameter)); } } }
/// <summary> /// Initializes a new converter given a command tree context. Initializes a new record layout cache. /// </summary> /// <param name="updateTranslator">Sets <see cref="m_updateTranslator" /></param> internal RecordConverter(UpdateTranslator updateTranslator) { m_updateTranslator = updateTranslator; }
internal ExtractorMetadata(EntitySetBase entitySetBase, StructuralType type, UpdateTranslator translator) { Contract.Requires(entitySetBase != null); Contract.Requires(type != null); Contract.Requires(translator != null); m_type = type; m_translator = translator; EntityType entityType = null; Set<EdmMember> keyMembers; Set<EdmMember> foreignKeyMembers; switch (type.BuiltInTypeKind) { case BuiltInTypeKind.RowType: // for row types (which are actually association end key records in disguise), all members // are keys keyMembers = new Set<EdmMember>(((RowType)type).Properties).MakeReadOnly(); foreignKeyMembers = Set<EdmMember>.Empty; break; case BuiltInTypeKind.EntityType: entityType = (EntityType)type; keyMembers = new Set<EdmMember>(entityType.KeyMembers).MakeReadOnly(); foreignKeyMembers = new Set<EdmMember>( ((EntitySet)entitySetBase).ForeignKeyDependents .SelectMany(fk => fk.Item2.ToProperties)).MakeReadOnly(); break; default: keyMembers = Set<EdmMember>.Empty; foreignKeyMembers = Set<EdmMember>.Empty; break; } var members = TypeHelpers.GetAllStructuralMembers(type); m_memberMap = new MemberInformation[members.Count]; // for each member, cache expensive to compute metadata information for (var ordinal = 0; ordinal < members.Count; ordinal++) { var member = members[ordinal]; // figure out flags for this member var flags = PropagatorFlags.NoFlags; var entityKeyOrdinal = default(int?); if (keyMembers.Contains(member)) { flags |= PropagatorFlags.Key; if (null != entityType) { entityKeyOrdinal = entityType.KeyMembers.IndexOf(member); } } if (foreignKeyMembers.Contains(member)) { flags |= PropagatorFlags.ForeignKey; } if (MetadataHelper.GetConcurrencyMode(member) == ConcurrencyMode.Fixed) { flags |= PropagatorFlags.ConcurrencyValue; } // figure out whether this member is mapped to any server generated // columns in the store var isServerGenerated = m_translator.ViewLoader.IsServerGen(entitySetBase, m_translator.MetadataWorkspace, member); // figure out whether member nullability is used as a condition in mapping var isNullConditionMember = m_translator.ViewLoader.IsNullConditionMember( entitySetBase, m_translator.MetadataWorkspace, member); // add information about this member m_memberMap[ordinal] = new MemberInformation( ordinal, entityKeyOrdinal, flags, member, isServerGenerated, isNullConditionMember); } }
private SourceInterpreter(UpdateTranslator translator, EntitySet sourceTable) { m_stateEntries = new List<IEntityStateEntry>(); m_translator = translator; m_sourceTable = sourceTable; }
/// <summary> /// Initialize an update compiler. /// </summary> /// <param name="translator"> Update context. </param> internal UpdateCompiler(UpdateTranslator translator) { m_translator = translator; }
protected virtual long GetRowsAffected(long rowsAffected, UpdateTranslator translator) { // if an explicit rows affected parameter exists, use this value instead if (null != _rowsAffectedParameter) { // by design, negative row counts indicate failure iff. an explicit rows // affected parameter is used if (DBNull.Value.Equals(_rowsAffectedParameter.Value)) { rowsAffected = 0; } else { try { rowsAffected = Convert.ToInt64(_rowsAffectedParameter.Value, CultureInfo.InvariantCulture); } catch (Exception e) { if (e.RequiresContext()) { // wrap the exception throw new UpdateException( Strings.Update_UnableToConvertRowsAffectedParameter( _rowsAffectedParameter.ParameterName, typeof(Int64).FullName), e, GetStateEntries(translator).Cast<ObjectStateEntry>().Distinct()); } throw; } } } return rowsAffected; }
private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName) { int columnOrdinal; try { columnOrdinal = reader.GetOrdinal(columnName); } catch (IndexOutOfRangeException) { throw new UpdateException( Strings.Update_MissingResultColumn(columnName), null, GetStateEntries(translator).Cast<ObjectStateEntry>().Distinct()); } return columnOrdinal; }
internal override IList<IEntityStateEntry> GetStateEntries(UpdateTranslator translator) { var stateEntries = new List<IEntityStateEntry>(2); if (null != OriginalValues) { foreach (var stateEntry in SourceInterpreter.GetAllStateEntries( OriginalValues, translator, Table)) { stateEntries.Add(stateEntry); } } if (null != CurrentValues) { foreach (var stateEntry in SourceInterpreter.GetAllStateEntries( CurrentValues, translator, Table)) { stateEntries.Add(stateEntry); } } return stateEntries; }
/// <summary> /// Gets state entries contributing to this function. Supports error reporting. /// </summary> internal override IList<IEntityStateEntry> GetStateEntries(UpdateTranslator translator) { return _stateEntries; }