// Determines key values for a list of changes. Side effect: populates <see cref="keys" /> which // includes an entry for every key involved in a change. private Dictionary <CompositeKey, PropagatorResult> ProcessKeys( UpdateCompiler compiler, List <PropagatorResult> changes, Set <CompositeKey> keys) { var map = new Dictionary <CompositeKey, PropagatorResult>( compiler.m_translator.KeyComparer); foreach (var change in changes) { // Reassign change to row since we cannot modify iteration variable var row = change; var key = new CompositeKey(GetKeyConstants(row)); // Make sure we aren't inserting another row with the same key PropagatorResult other; if (map.TryGetValue(key, out other)) { DiagnoseKeyCollision(compiler, change, key, other); } map.Add(key, row); keys.Add(key); } return(map); }
private DbExpression BuildPredicate( DbExpressionBinding target, PropagatorResult referenceRow, PropagatorResult current, TableChangeProcessor processor, ref bool rowMustBeTouched) { Dictionary <EdmProperty, PropagatorResult> dictionary = new Dictionary <EdmProperty, PropagatorResult>(); int ordinal = 0; foreach (EdmProperty property in processor.Table.ElementType.Properties) { PropagatorResult memberValue = referenceRow.GetMemberValue(ordinal); PropagatorResult input = current == null ? (PropagatorResult)null : current.GetMemberValue(ordinal); if (!rowMustBeTouched && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue))) { rowMustBeTouched = true; } if (!dictionary.ContainsKey(property) && (UpdateCompiler.HasFlag(memberValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || UpdateCompiler.HasFlag(input, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) { dictionary.Add(property, memberValue); } ++ordinal; } DbExpression left = (DbExpression)null; foreach (KeyValuePair <EdmProperty, PropagatorResult> keyValuePair in dictionary) { DbExpression equalityExpression = this.GenerateEqualityExpression(target, keyValuePair.Key, keyValuePair.Value); left = left != null ? (DbExpression)left.And(equalityExpression) : equalityExpression; } return(left); }
internal UpdateCommand BuildDeleteCommand( PropagatorResult oldRow, TableChangeProcessor processor) { bool rowMustBeTouched = true; DbExpressionBinding target = UpdateCompiler.GetTarget(processor); DbExpression predicate = this.BuildPredicate(target, oldRow, (PropagatorResult)null, processor, ref rowMustBeTouched); DbDeleteCommandTree deleteCommandTree = new DbDeleteCommandTree(this.m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate); return((UpdateCommand) new DynamicUpdateCommand(processor, this.m_translator, ModificationOperator.Delete, oldRow, (PropagatorResult)null, (DbModificationCommandTree)deleteCommandTree, (Dictionary <int, string>)null)); }
internal List <UpdateCommand> CompileCommands( ChangeNode changeNode, UpdateCompiler compiler) { Set <CompositeKey> keys = new Set <CompositeKey>(compiler.m_translator.KeyComparer); Dictionary <CompositeKey, PropagatorResult> dictionary1 = this.ProcessKeys(compiler, changeNode.Deleted, keys); Dictionary <CompositeKey, PropagatorResult> dictionary2 = this.ProcessKeys(compiler, changeNode.Inserted, keys); List <UpdateCommand> updateCommandList = new List <UpdateCommand>(dictionary1.Count + dictionary2.Count); foreach (CompositeKey key in keys) { PropagatorResult propagatorResult1; bool flag1 = dictionary1.TryGetValue(key, out propagatorResult1); PropagatorResult propagatorResult2; bool flag2 = dictionary2.TryGetValue(key, out propagatorResult2); try { if (!flag1) { updateCommandList.Add(compiler.BuildInsertCommand(propagatorResult2, this)); } else if (!flag2) { updateCommandList.Add(compiler.BuildDeleteCommand(propagatorResult1, this)); } else { UpdateCommand updateCommand = compiler.BuildUpdateCommand(propagatorResult1, propagatorResult2, this); if (updateCommand != null) { updateCommandList.Add(updateCommand); } } } catch (Exception ex) { if (ex.RequiresContext()) { List <IEntityStateEntry> source = new List <IEntityStateEntry>(); if (propagatorResult1 != null) { source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(propagatorResult1, compiler.m_translator, this.m_table)); } if (propagatorResult2 != null) { source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(propagatorResult2, compiler.m_translator, this.m_table)); } throw new UpdateException(Strings.Update_GeneralExecutionException, ex, source.Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>()); } throw; } } return(updateCommandList); }
private DbExpression GenerateEqualityExpression( DbExpressionBinding target, EdmProperty property, PropagatorResult value) { DbExpression propertyExpression = UpdateCompiler.GeneratePropertyExpression(target, property); DbExpression valueExpression = this.GenerateValueExpression(property, value); if (valueExpression.ExpressionKind == DbExpressionKind.Null) { return((DbExpression)propertyExpression.IsNull()); } return((DbExpression)propertyExpression.Equal(valueExpression)); }
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>()); }
internal UpdateCommand BuildInsertCommand( PropagatorResult newRow, TableChangeProcessor processor) { DbExpressionBinding target = UpdateCompiler.GetTarget(processor); bool rowMustBeTouched = true; List <DbModificationClause> modificationClauseList = new List <DbModificationClause>(); Dictionary <int, string> outputIdentifiers; DbExpression returning; foreach (DbModificationClause buildSetClause in this.BuildSetClauses(target, newRow, (PropagatorResult)null, processor, true, out outputIdentifiers, out returning, ref rowMustBeTouched)) { modificationClauseList.Add(buildSetClause); } DbInsertCommandTree insertCommandTree = new DbInsertCommandTree(this.m_translator.MetadataWorkspace, DataSpace.SSpace, target, new ReadOnlyCollection <DbModificationClause>((IList <DbModificationClause>)modificationClauseList), returning); return((UpdateCommand) new DynamicUpdateCommand(processor, this.m_translator, ModificationOperator.Insert, (PropagatorResult)null, newRow, (DbModificationCommandTree)insertCommandTree, outputIdentifiers)); }
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); }
internal UpdateCommand BuildUpdateCommand( PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor) { bool rowMustBeTouched = false; DbExpressionBinding target = UpdateCompiler.GetTarget(processor); List <DbModificationClause> modificationClauseList = new List <DbModificationClause>(); Dictionary <int, string> outputIdentifiers; DbExpression returning; foreach (DbModificationClause buildSetClause in this.BuildSetClauses(target, newRow, oldRow, processor, false, out outputIdentifiers, out returning, ref rowMustBeTouched)) { modificationClauseList.Add(buildSetClause); } DbExpression predicate = this.BuildPredicate(target, oldRow, newRow, processor, ref rowMustBeTouched); if (modificationClauseList.Count == 0) { if (rowMustBeTouched) { List <IEntityStateEntry> source = new List <IEntityStateEntry>(); source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(oldRow, this.m_translator, processor.Table)); source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(newRow, this.m_translator, processor.Table)); if (source.All <IEntityStateEntry>((Func <IEntityStateEntry, bool>)(it => it.State == EntityState.Unchanged))) { rowMustBeTouched = false; } } if (!rowMustBeTouched) { return((UpdateCommand)null); } } DbUpdateCommandTree updateCommandTree = new DbUpdateCommandTree(this.m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate, new ReadOnlyCollection <DbModificationClause>((IList <DbModificationClause>)modificationClauseList), returning); return((UpdateCommand) new DynamicUpdateCommand(processor, this.m_translator, ModificationOperator.Update, oldRow, newRow, (DbModificationCommandTree)updateCommandTree, outputIdentifiers)); }
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()); } }
// Processes all insert and delete requests in the table's <see cref="ChangeNode" />. Inserts // and deletes with the same key are merged into updates. internal List <UpdateCommand> CompileCommands(ChangeNode changeNode, UpdateCompiler compiler) { var keys = new Set <CompositeKey>(compiler.m_translator.KeyComparer); // Retrieve all delete results (original values) and insert results (current values) while // populating a set of all row keys. The set contains a single key per row. var deleteResults = ProcessKeys(compiler, changeNode.Deleted, keys); var insertResults = ProcessKeys(compiler, changeNode.Inserted, keys); var commands = new List <UpdateCommand>(deleteResults.Count + insertResults.Count); // Examine each row key to see if the row is being deleted, inserted or updated foreach (var key in keys) { PropagatorResult deleteResult; PropagatorResult insertResult; var hasDelete = deleteResults.TryGetValue(key, out deleteResult); var hasInsert = insertResults.TryGetValue(key, out insertResult); Debug.Assert( hasDelete || hasInsert, "(update/TableChangeProcessor) m_keys must not contain a value " + "if there is no corresponding insert or delete"); try { if (!hasDelete) { // this is an insert commands.Add(compiler.BuildInsertCommand(insertResult, this)); } else if (!hasInsert) { // this is a delete commands.Add(compiler.BuildDeleteCommand(deleteResult, this)); } else { // this is an update because it has both a delete result and an insert result var updateCommand = compiler.BuildUpdateCommand(deleteResult, insertResult, this); if (null != updateCommand) { // if null is returned, it means it is a no-op update commands.Add(updateCommand); } } } catch (Exception e) { if (e.RequiresContext()) { // collect state entries in scope for the current compilation var stateEntries = new List <IEntityStateEntry>(); if (null != deleteResult) { stateEntries.AddRange( SourceInterpreter.GetAllStateEntries( deleteResult, compiler.m_translator, m_table)); } if (null != insertResult) { stateEntries.AddRange( SourceInterpreter.GetAllStateEntries( insertResult, compiler.m_translator, m_table)); } throw new UpdateException( Strings.Update_GeneralExecutionException, e, stateEntries.Cast <ObjectStateEntry>().Distinct()); } throw; } } return(commands); }
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()); } }
// Determines key values for a list of changes. Side effect: populates <see cref="keys" /> which // includes an entry for every key involved in a change. private Dictionary<CompositeKey, PropagatorResult> ProcessKeys( UpdateCompiler compiler, List<PropagatorResult> changes, Set<CompositeKey> keys) { var map = new Dictionary<CompositeKey, PropagatorResult>( compiler.m_translator.KeyComparer); foreach (var change in changes) { // Reassign change to row since we cannot modify iteration variable var row = change; var key = new CompositeKey(GetKeyConstants(row)); // Make sure we aren't inserting another row with the same key PropagatorResult other; if (map.TryGetValue(key, out other)) { DiagnoseKeyCollision(compiler, change, key, other); } map.Add(key, row); keys.Add(key); } return map; }
// Processes all insert and delete requests in the table's <see cref="ChangeNode" />. Inserts // and deletes with the same key are merged into updates. internal List<UpdateCommand> CompileCommands(ChangeNode changeNode, UpdateCompiler compiler) { var keys = new Set<CompositeKey>(compiler.m_translator.KeyComparer); // Retrieve all delete results (original values) and insert results (current values) while // populating a set of all row keys. The set contains a single key per row. var deleteResults = ProcessKeys(compiler, changeNode.Deleted, keys); var insertResults = ProcessKeys(compiler, changeNode.Inserted, keys); var commands = new List<UpdateCommand>(deleteResults.Count + insertResults.Count); // Examine each row key to see if the row is being deleted, inserted or updated foreach (var key in keys) { PropagatorResult deleteResult; PropagatorResult insertResult; var hasDelete = deleteResults.TryGetValue(key, out deleteResult); var hasInsert = insertResults.TryGetValue(key, out insertResult); Debug.Assert( hasDelete || hasInsert, "(update/TableChangeProcessor) m_keys must not contain a value " + "if there is no corresponding insert or delete"); try { if (!hasDelete) { // this is an insert commands.Add(compiler.BuildInsertCommand(insertResult, this)); } else if (!hasInsert) { // this is a delete commands.Add(compiler.BuildDeleteCommand(deleteResult, this)); } else { // this is an update because it has both a delete result and an insert result var updateCommand = compiler.BuildUpdateCommand(deleteResult, insertResult, this); if (null != updateCommand) { // if null is returned, it means it is a no-op update commands.Add(updateCommand); } } } catch (Exception e) { if (e.RequiresContext()) { // collect state entries in scope for the current compilation var stateEntries = new List<IEntityStateEntry>(); if (null != deleteResult) { stateEntries.AddRange( SourceInterpreter.GetAllStateEntries( deleteResult, compiler.m_translator, m_table)); } if (null != insertResult) { stateEntries.AddRange( SourceInterpreter.GetAllStateEntries( insertResult, compiler.m_translator, m_table)); } throw new UpdateException( Strings.Update_GeneralExecutionException, e, stateEntries.Cast<ObjectStateEntry>().Distinct()); } throw; } } return commands; }
private IEnumerable <DbModificationClause> BuildSetClauses( DbExpressionBinding target, PropagatorResult row, PropagatorResult originalRow, TableChangeProcessor processor, bool insertMode, out Dictionary <int, string> outputIdentifiers, out DbExpression returning, ref bool rowMustBeTouched) { Dictionary <EdmProperty, PropagatorResult> dictionary = new Dictionary <EdmProperty, PropagatorResult>(); List <KeyValuePair <string, DbExpression> > keyValuePairList = new List <KeyValuePair <string, DbExpression> >(); outputIdentifiers = new Dictionary <int, string>(); PropagatorFlags propagatorFlags1 = insertMode ? PropagatorFlags.NoFlags : PropagatorFlags.Preserve | PropagatorFlags.Unknown; for (int index1 = 0; index1 < processor.Table.ElementType.Properties.Count; ++index1) { EdmProperty property = processor.Table.ElementType.Properties[index1]; PropagatorResult result = row.GetMemberValue(index1); if (-1 != result.Identifier) { result = result.ReplicateResultWithNewValue(this.m_translator.KeyManager.GetPrincipalValue(result)); } bool flag1 = false; bool flag2 = false; for (int index2 = 0; index2 < processor.KeyOrdinals.Length; ++index2) { if (processor.KeyOrdinals[index2] == index1) { flag2 = true; break; } } PropagatorFlags propagatorFlags2 = PropagatorFlags.NoFlags; if (!insertMode && flag2) { flag1 = true; } else { propagatorFlags2 |= result.PropagatorFlags; } StoreGeneratedPattern generatedPattern = MetadataHelper.GetStoreGeneratedPattern((EdmMember)property); bool flag3 = generatedPattern == StoreGeneratedPattern.Computed || insertMode && generatedPattern == StoreGeneratedPattern.Identity; if (flag3) { DbPropertyExpression propertyExpression = target.Variable.Property(property); keyValuePairList.Add(new KeyValuePair <string, DbExpression>(property.Name, (DbExpression)propertyExpression)); int identifier = result.Identifier; if (-1 != identifier) { if (this.m_translator.KeyManager.HasPrincipals(identifier)) { throw new InvalidOperationException(Strings.Update_GeneratedDependent((object)property.Name)); } outputIdentifiers.Add(identifier, property.Name); if (generatedPattern != StoreGeneratedPattern.Identity && processor.IsKeyProperty(index1)) { throw new NotSupportedException(Strings.Update_NotSupportedComputedKeyColumn((object)"StoreGeneratedPattern", (object)"Computed", (object)"Identity", (object)property.Name, (object)property.DeclaringType.FullName)); } } } if ((propagatorFlags2 & propagatorFlags1) != PropagatorFlags.NoFlags) { flag1 = true; } else if (flag3) { flag1 = true; rowMustBeTouched = true; } if (!flag1 && !insertMode && generatedPattern == StoreGeneratedPattern.Identity) { PropagatorResult memberValue = originalRow.GetMemberValue(index1); if (!ByValueEqualityComparer.Default.Equals(memberValue.GetSimpleValue(), result.GetSimpleValue())) { throw new InvalidOperationException(Strings.Update_ModifyingIdentityColumn((object)"Identity", (object)property.Name, (object)property.DeclaringType.FullName)); } flag1 = true; } if (!flag1) { dictionary.Add(property, result); } } returning = 0 >= keyValuePairList.Count ? (DbExpression)null : (DbExpression)DbExpressionBuilder.NewRow((IEnumerable <KeyValuePair <string, DbExpression> >)keyValuePairList); List <DbModificationClause> modificationClauseList = new List <DbModificationClause>(dictionary.Count); foreach (KeyValuePair <EdmProperty, PropagatorResult> keyValuePair in dictionary) { EdmProperty key = keyValuePair.Key; modificationClauseList.Add((DbModificationClause) new DbSetClause(UpdateCompiler.GeneratePropertyExpression(target, keyValuePair.Key), this.GenerateValueExpression(keyValuePair.Key, keyValuePair.Value))); } return((IEnumerable <DbModificationClause>)modificationClauseList); }