private void DiagnoseKeyCollision( UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other) { KeyManager keyManager = compiler.m_translator.KeyManager; CompositeKey compositeKey = new CompositeKey(this.GetKeyConstants(other)); bool flag = true; for (int index = 0; flag && index < key.KeyComponents.Length; ++index) { int identifier1 = key.KeyComponents[index].Identifier; int identifier2 = compositeKey.KeyComponents[index].Identifier; if (!keyManager.GetPrincipals(identifier1).Intersect <int>(keyManager.GetPrincipals(identifier2)).Any <int>()) { flag = false; } } if (flag) { throw new UpdateException(Strings.Update_DuplicateKeys, (Exception)null, SourceInterpreter.GetAllStateEntries(change, compiler.m_translator, this.m_table).Concat <IEntityStateEntry>((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(other, compiler.m_translator, this.m_table)).Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>()); } HashSet <IEntityStateEntry> source = (HashSet <IEntityStateEntry>)null; foreach (PropagatorResult propagatorResult in ((IEnumerable <PropagatorResult>)key.KeyComponents).Concat <PropagatorResult>((IEnumerable <PropagatorResult>)compositeKey.KeyComponents)) { HashSet <IEntityStateEntry> entityStateEntrySet = new HashSet <IEntityStateEntry>(); foreach (int dependent in keyManager.GetDependents(propagatorResult.Identifier)) { PropagatorResult owner; if (keyManager.TryGetIdentifierOwner(dependent, out owner) && owner.StateEntry != null) { entityStateEntrySet.Add(owner.StateEntry); } } if (source == null) { source = new HashSet <IEntityStateEntry>((IEnumerable <IEntityStateEntry>)entityStateEntrySet); } else { source.IntersectWith((IEnumerable <IEntityStateEntry>)entityStateEntrySet); } } throw new UpdateException(Strings.Update_GeneralExecutionException, (Exception) new ConstraintException(Strings.Update_ReferentialConstraintIntegrityViolation), source.Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>()); }
private Dictionary <CompositeKey, PropagatorResult> ProcessKeys( UpdateCompiler compiler, List <PropagatorResult> changes, Set <CompositeKey> keys) { Dictionary <CompositeKey, PropagatorResult> dictionary = new Dictionary <CompositeKey, PropagatorResult>(compiler.m_translator.KeyComparer); foreach (PropagatorResult change in changes) { PropagatorResult row = change; CompositeKey compositeKey = new CompositeKey(this.GetKeyConstants(row)); PropagatorResult other; if (dictionary.TryGetValue(compositeKey, out other)) { this.DiagnoseKeyCollision(compiler, change, compositeKey, other); } dictionary.Add(compositeKey, row); keys.Add(compositeKey); } return(dictionary); }
// <summary> // Constructor // </summary> // <param name="metadata"> Sets Metadata </param> // <param name="record"> Record containing key value </param> // <param name="isTarget"> Indicates whether the source or target end of the constraint is being pulled </param> // <param name="isInsert"> Indicates whether this is an insert dependency or a delete dependency </param> private ForeignKeyValue( ReferentialConstraint metadata, PropagatorResult record, bool isTarget, bool isInsert) { Metadata = metadata; // construct key IList <EdmProperty> keyProperties = isTarget ? metadata.FromProperties : metadata.ToProperties; var keyValues = new PropagatorResult[keyProperties.Count]; var hasNullMember = false; for (var i = 0; i < keyValues.Length; i++) { keyValues[i] = record.GetMemberValue(keyProperties[i]); if (keyValues[i].IsNull) { hasNullMember = true; break; } } if (hasNullMember) { // set key to null to indicate that it is not behaving as a key // (in SQL, keys with null parts do not participate in constraints) Key = null; } else { Key = new CompositeKey(keyValues); } IsInsert = isInsert; }
private ForeignKeyValue( ReferentialConstraint metadata, PropagatorResult record, bool isTarget, bool isInsert) { this.Metadata = metadata; IList <EdmProperty> edmPropertyList = isTarget ? (IList <EdmProperty>)metadata.FromProperties : (IList <EdmProperty>)metadata.ToProperties; PropagatorResult[] constants = new PropagatorResult[edmPropertyList.Count]; bool flag = false; for (int index = 0; index < constants.Length; ++index) { constants[index] = record.GetMemberValue((EdmMember)edmPropertyList[index]); if (constants[index].IsNull) { flag = true; break; } } this.Key = !flag ? new CompositeKey(constants) : (CompositeKey)null; this.IsInsert = isInsert; }
private void DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other) { var keyManager = compiler.m_translator.KeyManager; var otherKey = new CompositeKey(GetKeyConstants(other)); // determine if the conflict is due to shared principal key values var sharedPrincipal = true; for (var i = 0; sharedPrincipal && i < key.KeyComponents.Length; i++) { var identifier1 = key.KeyComponents[i].Identifier; var identifier2 = otherKey.KeyComponents[i].Identifier; if (!keyManager.GetPrincipals(identifier1).Intersect(keyManager.GetPrincipals(identifier2)).Any()) { sharedPrincipal = false; } } if (sharedPrincipal) { // if the duplication is due to shared principals, there is a duplicate key exception var stateEntries = SourceInterpreter.GetAllStateEntries(change, compiler.m_translator, m_table) .Concat(SourceInterpreter.GetAllStateEntries(other, compiler.m_translator, m_table)); throw new UpdateException(Strings.Update_DuplicateKeys, null, stateEntries.Cast <ObjectStateEntry>().Distinct()); } else { // if there are no shared principals, it implies that common dependents are the problem HashSet <IEntityStateEntry> commonDependents = null; foreach (var keyValue in key.KeyComponents.Concat(otherKey.KeyComponents)) { var dependents = new HashSet <IEntityStateEntry>(); foreach (var dependentId in keyManager.GetDependents(keyValue.Identifier)) { PropagatorResult dependentResult; if (keyManager.TryGetIdentifierOwner(dependentId, out dependentResult) && null != dependentResult.StateEntry) { dependents.Add(dependentResult.StateEntry); } } if (null == commonDependents) { commonDependents = new HashSet <IEntityStateEntry>(dependents); } else { commonDependents.IntersectWith(dependents); } } // to ensure the exception shape is consistent with constraint violations discovered while processing // commands (a more conventional scenario in which different tables are contributing principal values) // wrap a DataConstraintException in an UpdateException throw new UpdateException( Strings.Update_GeneralExecutionException, new ConstraintException(Strings.Update_ReferentialConstraintIntegrityViolation), commonDependents.Cast <ObjectStateEntry>().Distinct()); } }
// <summary> // See <see cref="LeftPlaceholder" /> // </summary> private PropagatorResult RightPlaceholder(CompositeKey key, PopulateMode mode) { return(PlaceholderPopulator.Populate(m_right.Placeholder, key, m_rightPlaceholderKey, mode)); }
// <summary> // Propagate all changes associated with a particular join key. // </summary> // <param name="key"> Key. </param> // <param name="result"> Resulting changes are added to this result. </param> private void Propagate( CompositeKey key, ChangeNode result, JoinDictionary leftDeletes, JoinDictionary leftInserts, JoinDictionary rightDeletes, JoinDictionary rightInserts) { // Retrieve changes associates with this join key Tuple <CompositeKey, PropagatorResult> leftInsert = null; Tuple <CompositeKey, PropagatorResult> leftDelete = null; Tuple <CompositeKey, PropagatorResult> rightInsert = null; Tuple <CompositeKey, PropagatorResult> rightDelete = null; var input = Ops.Nothing; if (leftInserts.TryGetValue(key, out leftInsert)) { input |= Ops.LeftInsert; } if (leftDeletes.TryGetValue(key, out leftDelete)) { input |= Ops.LeftDelete; } if (rightInserts.TryGetValue(key, out rightInsert)) { input |= Ops.RightInsert; } if (rightDeletes.TryGetValue(key, out rightDelete)) { input |= Ops.RightDelete; } // Get propagation rules for the changes var insertRule = m_insertRules[input]; var deleteRule = m_deleteRules[input]; if (Ops.Unsupported == insertRule || Ops.Unsupported == deleteRule) { // If no propagation rules are defined, it suggests an invalid workload (e.g. // a required entity or relationship is missing). In general, such exceptions // should be caught by the RelationshipConstraintValidator, but we defensively // check for problems here regardless. For instance, a 0..1:1..1 self-assocation // implied a stronger constraint that cannot be checked by RelationshipConstraintValidator. // First gather state entries contributing to the problem var stateEntries = new List <IEntityStateEntry>(); Action <Tuple <CompositeKey, PropagatorResult> > addStateEntries = (r) => { if (r != null) { stateEntries.AddRange( SourceInterpreter.GetAllStateEntries( r.Item2, m_parent.m_updateTranslator, m_parent.m_table)); } }; addStateEntries(leftInsert); addStateEntries(leftDelete); addStateEntries(rightInsert); addStateEntries(rightDelete); throw new UpdateException(Strings.Update_InvalidChanges, null, stateEntries.Cast <ObjectStateEntry>().Distinct()); } // Where needed, substitute null/unknown placeholders. In some of the join propagation // rules, we handle the case where a side of the join is 'unknown', or where one side // of a join is comprised of an record containing only nulls. For instance, we may update // only one extent appearing in a row of a table (unknown), or; we may insert only // the left hand side of a left outer join, in which case the right hand side is 'null'. if (0 != (Ops.LeftUnknown & insertRule)) { leftInsert = Tuple.Create(key, LeftPlaceholder(key, PopulateMode.Unknown)); } if (0 != (Ops.LeftUnknown & deleteRule)) { leftDelete = Tuple.Create(key, LeftPlaceholder(key, PopulateMode.Unknown)); } if (0 != (Ops.RightNullModified & insertRule)) { rightInsert = Tuple.Create(key, RightPlaceholder(key, PopulateMode.NullModified)); } else if (0 != (Ops.RightNullPreserve & insertRule)) { rightInsert = Tuple.Create(key, RightPlaceholder(key, PopulateMode.NullPreserve)); } else if (0 != (Ops.RightUnknown & insertRule)) { rightInsert = Tuple.Create(key, RightPlaceholder(key, PopulateMode.Unknown)); } if (0 != (Ops.RightNullModified & deleteRule)) { rightDelete = Tuple.Create(key, RightPlaceholder(key, PopulateMode.NullModified)); } else if (0 != (Ops.RightNullPreserve & deleteRule)) { rightDelete = Tuple.Create(key, RightPlaceholder(key, PopulateMode.NullPreserve)); } else if (0 != (Ops.RightUnknown & deleteRule)) { rightDelete = Tuple.Create(key, RightPlaceholder(key, PopulateMode.Unknown)); } // Populate elements in join output if (null != leftInsert && null != rightInsert) { result.Inserted.Add(CreateResultTuple(leftInsert, rightInsert, result)); } if (null != leftDelete && null != rightDelete) { result.Deleted.Add(CreateResultTuple(leftDelete, rightDelete, result)); } }