internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { if (null == m_mapping) { return(null); } bool isInsert = EntityState.Added == stateEntry.State; EntityUtil.ValidateNecessaryModificationFunctionMapping( isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping, isInsert ? "Insert" : "Delete", stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name); // initialize a new command StorageModificationFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping; FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry); // extract the relationship values from the state entry PropagatorResult recordResult; if (isInsert) { recordResult = stateEntry.Current; } else { recordResult = stateEntry.Original; } // bind parameters foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings) { // extract the relationship information Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " + "path should include the relationship end and key property only"); EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; AssociationEndMember endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1]; // get the end member PropagatorResult endResult = recordResult.GetMemberValue(endMember); PropagatorResult keyResult = endResult.GetMemberValue(keyProperty); command.SetParameterValue(keyResult, parameterBinding, translator); } // add rows affected output parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); return(command); }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { var mapping = GetFunctionMapping(stateEntry); StorageEntityTypeModificationFunctionMapping typeMapping = mapping.Item1; StorageModificationFunctionMapping functionMapping = mapping.Item2; EntityKey entityKey = stateEntry.Source.EntityKey; var stateEntries = new HashSet<IEntityStateEntry> { stateEntry.Source }; // gather all referenced association ends var collocatedEntries = // find all related entries corresponding to collocated association types from end in functionMapping.CollocatedAssociationSetEnds join candidateEntry in translator.GetRelationships(entityKey) on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry); var currentReferenceEnds = new Dictionary<AssociationEndMember, IEntityStateEntry>(); var originalReferenceEnds = new Dictionary<AssociationEndMember, IEntityStateEntry>(); foreach (var candidate in collocatedEntries) { ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2); } // create function object FunctionUpdateCommand command; // consider the following scenario, we need to loop through all the state entries that is correlated with entity2 and make sure it is not changed. // entity1 <-- Independent Association <-- entity2 <-- Fk association <-- entity 3 // | // entity4 <-- Fk association <-- if (stateEntries.All(e => e.State == EntityState.Unchanged)) { // we shouldn't update the entity if it is unchanged, only update when referenced association is changed. // if not, then this will trigger a fake update for principal end as describe in bug 894569. command = null; } else { command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry); // bind all function parameters BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds); // interpret all result bindings if (null != functionMapping.ResultBindings) { foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings) { PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property); command.AddResultColumn(translator, resultBinding.ColumnName, result); } } } return command; }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { if (null == m_mapping) { return null; } bool isInsert = EntityState.Added == stateEntry.State; EntityUtil.ValidateNecessaryModificationFunctionMapping( isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping, isInsert ? "Insert" : "Delete", stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name); // initialize a new command StorageModificationFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping; FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry); // extract the relationship values from the state entry PropagatorResult recordResult; if (isInsert) { recordResult = stateEntry.Current; } else { recordResult = stateEntry.Original; } // bind parameters foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings) { // extract the relationship information Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " + "path should include the relationship end and key property only"); EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; AssociationEndMember endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1]; // get the end member PropagatorResult endResult = recordResult.GetMemberValue(endMember); PropagatorResult keyResult = endResult.GetMemberValue(keyProperty); command.SetParameterValue(keyResult, parameterBinding, translator); } // add rows affected output parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); return command; }
// Walks through all parameter bindings in the function mapping and binds the parameters to the // requested properties of the given state entry. private void BindFunctionParameters(UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageModificationFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary<AssociationEndMember, IEntityStateEntry> currentReferenceEnds, Dictionary<AssociationEndMember, IEntityStateEntry> originalReferenceEnds) { // bind all parameters foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings) { PropagatorResult result; // extract value if (null != parameterBinding.MemberPath.AssociationSetEnd) { // find the relationship entry corresponding to the navigation AssociationEndMember endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember; IEntityStateEntry relationshipEntry; bool hasTarget = parameterBinding.IsCurrent ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry) : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry); if (!hasTarget) { if (endMember.RelationshipMultiplicity == RelationshipMultiplicity.One) { string entitySetName = stateEntry.Source.EntitySet.Name; string associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name; throw EntityUtil.Update(Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName), null, command.GetStateEntries(translator)); } else { result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null); } } else { // get the actual value PropagatorResult relationshipResult = parameterBinding.IsCurrent ? translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified) : translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified); PropagatorResult endResult = relationshipResult.GetMemberValue(endMember); EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; result = endResult.GetMemberValue(keyProperty); } } else { // walk through the member path to find the appropriate propagator results result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original; for (int i = parameterBinding.MemberPath.Members.Count; i > 0;) { --i; EdmMember member = parameterBinding.MemberPath.Members[i]; result = result.GetMemberValue(member); } } // create DbParameter command.SetParameterValue(result, parameterBinding, translator); } // Add rows affected parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); }
internal override FunctionUpdateCommand Translate( UpdateTranslator translator, ExtractedStateEntry stateEntry) { var mapping = GetFunctionMapping(stateEntry); StorageEntityTypeModificationFunctionMapping typeMapping = mapping.Item1; StorageModificationFunctionMapping functionMapping = mapping.Item2; EntityKey entityKey = stateEntry.Source.EntityKey; var stateEntries = new HashSet <IEntityStateEntry> { stateEntry.Source }; // gather all referenced association ends var collocatedEntries = // find all related entries corresponding to collocated association types from end in functionMapping.CollocatedAssociationSetEnds join candidateEntry in translator.GetRelationships(entityKey) on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry); var currentReferenceEnds = new Dictionary <AssociationEndMember, IEntityStateEntry>(); var originalReferenceEnds = new Dictionary <AssociationEndMember, IEntityStateEntry>(); foreach (var candidate in collocatedEntries) { ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2); } // create function object FunctionUpdateCommand command; // consider the following scenario, we need to loop through all the state entries that is correlated with entity2 and make sure it is not changed. // entity1 <-- Independent Association <-- entity2 <-- Fk association <-- entity 3 // | // entity4 <-- Fk association <-- if (stateEntries.All(e => e.State == EntityState.Unchanged)) { // we shouldn't update the entity if it is unchanged, only update when referenced association is changed. // if not, then this will trigger a fake update for principal end as describe in command = null; } else { command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry); // bind all function parameters BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds); // interpret all result bindings if (null != functionMapping.ResultBindings) { foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings) { PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property); command.AddResultColumn(translator, resultBinding.ColumnName, result); } } } return(command); }
// Walks through all parameter bindings in the function mapping and binds the parameters to the // requested properties of the given state entry. private void BindFunctionParameters(UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageModificationFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary <AssociationEndMember, IEntityStateEntry> currentReferenceEnds, Dictionary <AssociationEndMember, IEntityStateEntry> originalReferenceEnds) { // bind all parameters foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings) { PropagatorResult result; // extract value if (null != parameterBinding.MemberPath.AssociationSetEnd) { // find the relationship entry corresponding to the navigation AssociationEndMember endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember; IEntityStateEntry relationshipEntry; bool hasTarget = parameterBinding.IsCurrent ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry) : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry); if (!hasTarget) { if (endMember.RelationshipMultiplicity == RelationshipMultiplicity.One) { string entitySetName = stateEntry.Source.EntitySet.Name; string associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name; throw EntityUtil.Update(Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName), null, command.GetStateEntries(translator)); } else { result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null); } } else { // get the actual value PropagatorResult relationshipResult = parameterBinding.IsCurrent ? translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified) : translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified); PropagatorResult endResult = relationshipResult.GetMemberValue(endMember); EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; result = endResult.GetMemberValue(keyProperty); } } else { // walk through the member path to find the appropriate propagator results result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original; for (int i = parameterBinding.MemberPath.Members.Count; i > 0;) { --i; EdmMember member = parameterBinding.MemberPath.Members[i]; result = result.GetMemberValue(member); } } // create DbParameter command.SetParameterValue(result, parameterBinding, translator); } // Add rows affected parameter command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter); }
internal override int CompareToType(UpdateCommand otherCommand) { Debug.Assert(!object.ReferenceEquals(this, otherCommand), "caller should ensure other command is different"); FunctionUpdateCommand other = (FunctionUpdateCommand)otherCommand; // first state entry is the 'main' state entry for the command (see ctor) IEntityStateEntry thisParent = this.m_stateEntries[0]; IEntityStateEntry otherParent = other.m_stateEntries[0]; // order by operator int result = (int)GetModificationOperator(thisParent.State) - (int)GetModificationOperator(otherParent.State); if (0 != result) { return(result); } // order by entity set result = StringComparer.Ordinal.Compare(thisParent.EntitySet.Name, otherParent.EntitySet.Name); if (0 != result) { return(result); } result = StringComparer.Ordinal.Compare(thisParent.EntitySet.EntityContainer.Name, otherParent.EntitySet.EntityContainer.Name); if (0 != result) { return(result); } // order by key values int thisInputIdentifierCount = (null == this.m_inputIdentifiers ? 0 : this.m_inputIdentifiers.Count); int otherInputIdentifierCount = (null == other.m_inputIdentifiers ? 0 : other.m_inputIdentifiers.Count); result = thisInputIdentifierCount - otherInputIdentifierCount; if (0 != result) { return(result); } for (int i = 0; i < thisInputIdentifierCount; i++) { DbParameter thisParameter = this.m_inputIdentifiers[i].Value; DbParameter otherParameter = other.m_inputIdentifiers[i].Value; result = ByValueComparer.Default.Compare(thisParameter.Value, otherParameter.Value); if (0 != result) { return(result); } } // If the result is still zero, it means key values are all the same. Switch to synthetic identifiers // to differentiate. for (int i = 0; i < thisInputIdentifierCount; i++) { int thisIdentifier = this.m_inputIdentifiers[i].Key; int otherIdentifier = other.m_inputIdentifiers[i].Key; result = thisIdentifier - otherIdentifier; if (0 != result) { return(result); } } return(result); }