Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / TableChangeProcessor.cs / 1305376 / TableChangeProcessor.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Metadata.Edm; using System.Collections.Generic; using System.Data.Common; using System.Data.Common.Utils; using System.Diagnostics; using System.Data.Entity; using System.Linq; namespace System.Data.Mapping.Update.Internal { ////// Processes changes applying to a table by merging inserts and deletes into updates /// where appropriate. /// ////// This class is essentially responsible for identifying inserts, deletes /// and updates in a particular table based on the internal class TableChangeProcessor { #region Constructors ////// produced by value propagation w.r.t. the update mapping view for that table. /// Assumes the change node includes at most a single insert and at most a single delete /// for a given key (where we have both, the change is treated as an update). /// /// Constructs processor based on the contents of a change node. /// /// Table for which changes are being processed. internal TableChangeProcessor(EntitySet table) { EntityUtil.CheckArgumentNull(table, "table"); m_table = table; // cache information about table key m_keyOrdinals = InitializeKeyOrdinals(table); } #endregion #region Fields private readonly EntitySet m_table; private readonly int[] m_keyOrdinals; #endregion #region Properties ////// Gets metadata for the table being modified. /// internal EntitySet Table { get { return m_table; } } ////// Gets a map from column ordinal to property descriptions for columns that are components of the table's /// primary key. /// internal int[] KeyOrdinals { get { return m_keyOrdinals; } } #endregion #region Methods // Determines whether the given ordinal position in the property list // for this table is a key value. internal bool IsKeyProperty(int propertyOrdinal) { foreach (int keyOrdinal in m_keyOrdinals) { if (propertyOrdinal == keyOrdinal) { return true; } } return false; } // Determines which column ordinals in the table are part of the key. private static int[] InitializeKeyOrdinals(EntitySet table) { EntityType tableType = table.ElementType; IListkeyMembers = tableType.KeyMembers; IBaseList members = TypeHelpers.GetAllStructuralMembers(tableType); int[] keyOrdinals = new int[keyMembers.Count]; for (int keyMemberIndex = 0; keyMemberIndex < keyMembers.Count; keyMemberIndex++) { EdmMember keyMember = keyMembers[keyMemberIndex]; keyOrdinals[keyMemberIndex] = members.IndexOf(keyMember); Debug.Assert(keyOrdinals[keyMemberIndex] >= 0 && keyOrdinals[keyMemberIndex] < members.Count, "an EntityType key member must also be a member of the entity type"); } return keyOrdinals; } // Processes all insert and delete requests in the table's . Inserts // and deletes with the same key are merged into updates. internal List CompileCommands(ChangeNode changeNode, UpdateCompiler compiler) { Set keys = new Set (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. Dictionary deleteResults = ProcessKeys(compiler, changeNode.Deleted, keys); Dictionary insertResults = ProcessKeys(compiler, changeNode.Inserted, keys); List commands = new List (deleteResults.Count + insertResults.Count); // Examine each row key to see if the row is being deleted, inserted or updated foreach (CompositeKey key in keys) { PropagatorResult deleteResult; PropagatorResult insertResult; bool hasDelete = deleteResults.TryGetValue(key, out deleteResult); bool 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 UpdateCommand 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 (UpdateTranslator.RequiresContext(e)) { // collect state entries in scope for the current compilation List stateEntries = new List (); 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 EntityUtil.Update(System.Data.Entity.Strings.Update_GeneralExecutionException, e, stateEntries); } throw; } } return commands; } // Determines key values for a list of changes. Side effect: populates which // includes an entry for every key involved in a change. private Dictionary ProcessKeys(UpdateCompiler compiler, List changes, Set keys) { Dictionary map = new Dictionary ( compiler.m_translator.KeyComparer); foreach (PropagatorResult change in changes) { // Reassign change to row since we cannot modify iteration variable PropagatorResult row = change; CompositeKey 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 void DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other) { KeyManager keyManager = compiler.m_translator.KeyManager; CompositeKey otherKey = new CompositeKey(GetKeyConstants(other)); // determine if the conflict is due to shared principal key values bool sharedPrincipal = true; for (int i = 0; sharedPrincipal && i < key.KeyComponents.Length; i++) { int identifier1 = key.KeyComponents[i].Identifier; int 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 EntityUtil.Update(Strings.Update_DuplicateKeys, null, stateEntries); } else { // if there are no shared principals, it implies that common dependents are the problem HashSet commonDependents = null; foreach (PropagatorResult keyValue in key.KeyComponents.Concat(otherKey.KeyComponents)) { var dependents = new HashSet (); foreach (int 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 (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 EntityUtil.Update(Strings.Update_GeneralExecutionException, EntityUtil.Constraint(Strings.Update_ReferentialConstraintIntegrityViolation), commonDependents); } } // Extracts key constants from the given row. private PropagatorResult[] GetKeyConstants(PropagatorResult row) { PropagatorResult[] keyConstants = new PropagatorResult[m_keyOrdinals.Length]; for (int i = 0; i < m_keyOrdinals.Length; i++) { PropagatorResult constant = row.GetMemberValue(m_keyOrdinals[i]); keyConstants[i] = constant; } return keyConstants; } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Metadata.Edm; using System.Collections.Generic; using System.Data.Common; using System.Data.Common.Utils; using System.Diagnostics; using System.Data.Entity; using System.Linq; namespace System.Data.Mapping.Update.Internal { ////// Processes changes applying to a table by merging inserts and deletes into updates /// where appropriate. /// ////// This class is essentially responsible for identifying inserts, deletes /// and updates in a particular table based on the internal class TableChangeProcessor { #region Constructors ////// produced by value propagation w.r.t. the update mapping view for that table. /// Assumes the change node includes at most a single insert and at most a single delete /// for a given key (where we have both, the change is treated as an update). /// /// Constructs processor based on the contents of a change node. /// /// Table for which changes are being processed. internal TableChangeProcessor(EntitySet table) { EntityUtil.CheckArgumentNull(table, "table"); m_table = table; // cache information about table key m_keyOrdinals = InitializeKeyOrdinals(table); } #endregion #region Fields private readonly EntitySet m_table; private readonly int[] m_keyOrdinals; #endregion #region Properties ////// Gets metadata for the table being modified. /// internal EntitySet Table { get { return m_table; } } ////// Gets a map from column ordinal to property descriptions for columns that are components of the table's /// primary key. /// internal int[] KeyOrdinals { get { return m_keyOrdinals; } } #endregion #region Methods // Determines whether the given ordinal position in the property list // for this table is a key value. internal bool IsKeyProperty(int propertyOrdinal) { foreach (int keyOrdinal in m_keyOrdinals) { if (propertyOrdinal == keyOrdinal) { return true; } } return false; } // Determines which column ordinals in the table are part of the key. private static int[] InitializeKeyOrdinals(EntitySet table) { EntityType tableType = table.ElementType; IListkeyMembers = tableType.KeyMembers; IBaseList members = TypeHelpers.GetAllStructuralMembers(tableType); int[] keyOrdinals = new int[keyMembers.Count]; for (int keyMemberIndex = 0; keyMemberIndex < keyMembers.Count; keyMemberIndex++) { EdmMember keyMember = keyMembers[keyMemberIndex]; keyOrdinals[keyMemberIndex] = members.IndexOf(keyMember); Debug.Assert(keyOrdinals[keyMemberIndex] >= 0 && keyOrdinals[keyMemberIndex] < members.Count, "an EntityType key member must also be a member of the entity type"); } return keyOrdinals; } // Processes all insert and delete requests in the table's . Inserts // and deletes with the same key are merged into updates. internal List CompileCommands(ChangeNode changeNode, UpdateCompiler compiler) { Set keys = new Set (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. Dictionary deleteResults = ProcessKeys(compiler, changeNode.Deleted, keys); Dictionary insertResults = ProcessKeys(compiler, changeNode.Inserted, keys); List commands = new List (deleteResults.Count + insertResults.Count); // Examine each row key to see if the row is being deleted, inserted or updated foreach (CompositeKey key in keys) { PropagatorResult deleteResult; PropagatorResult insertResult; bool hasDelete = deleteResults.TryGetValue(key, out deleteResult); bool 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 UpdateCommand 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 (UpdateTranslator.RequiresContext(e)) { // collect state entries in scope for the current compilation List stateEntries = new List (); 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 EntityUtil.Update(System.Data.Entity.Strings.Update_GeneralExecutionException, e, stateEntries); } throw; } } return commands; } // Determines key values for a list of changes. Side effect: populates which // includes an entry for every key involved in a change. private Dictionary ProcessKeys(UpdateCompiler compiler, List changes, Set keys) { Dictionary map = new Dictionary ( compiler.m_translator.KeyComparer); foreach (PropagatorResult change in changes) { // Reassign change to row since we cannot modify iteration variable PropagatorResult row = change; CompositeKey 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 void DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other) { KeyManager keyManager = compiler.m_translator.KeyManager; CompositeKey otherKey = new CompositeKey(GetKeyConstants(other)); // determine if the conflict is due to shared principal key values bool sharedPrincipal = true; for (int i = 0; sharedPrincipal && i < key.KeyComponents.Length; i++) { int identifier1 = key.KeyComponents[i].Identifier; int 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 EntityUtil.Update(Strings.Update_DuplicateKeys, null, stateEntries); } else { // if there are no shared principals, it implies that common dependents are the problem HashSet commonDependents = null; foreach (PropagatorResult keyValue in key.KeyComponents.Concat(otherKey.KeyComponents)) { var dependents = new HashSet (); foreach (int 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 (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 EntityUtil.Update(Strings.Update_GeneralExecutionException, EntityUtil.Constraint(Strings.Update_ReferentialConstraintIntegrityViolation), commonDependents); } } // Extracts key constants from the given row. private PropagatorResult[] GetKeyConstants(PropagatorResult row) { PropagatorResult[] keyConstants = new PropagatorResult[m_keyOrdinals.Length]; for (int i = 0; i < m_keyOrdinals.Length; i++) { PropagatorResult constant = row.GetMemberValue(m_keyOrdinals[i]); keyConstants[i] = constant; } return keyConstants; } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- basevalidator.cs
- OleDbConnectionInternal.cs
- CalendarBlackoutDatesCollection.cs
- BindingCompleteEventArgs.cs
- SmiEventSink_Default.cs
- FontStretchConverter.cs
- IndexExpression.cs
- ISAPIWorkerRequest.cs
- NavigateEvent.cs
- LeaseManager.cs
- _StreamFramer.cs
- StrokeNodeData.cs
- CombinedGeometry.cs
- LoadWorkflowCommand.cs
- StyleReferenceConverter.cs
- ServiceBehaviorAttribute.cs
- ImageButton.cs
- Enum.cs
- ItemsPresenter.cs
- PropertyConverter.cs
- XmlDocumentFragment.cs
- CultureTable.cs
- AssertSection.cs
- GrammarBuilderPhrase.cs
- ContextMenuService.cs
- FastEncoderWindow.cs
- DiscoveryClientOutputChannel.cs
- PageBreakRecord.cs
- BuildProvider.cs
- XmlChoiceIdentifierAttribute.cs
- TheQuery.cs
- AppSettingsSection.cs
- MultiSelectRootGridEntry.cs
- PathSegmentCollection.cs
- SessionParameter.cs
- ReaderOutput.cs
- DiscoveryClientProtocol.cs
- httpapplicationstate.cs
- AttributeUsageAttribute.cs
- TransactionManager.cs
- SecurityTokenParameters.cs
- PagesSection.cs
- TypeSemantics.cs
- TypeConverterValueSerializer.cs
- AsymmetricKeyExchangeFormatter.cs
- MdiWindowListStrip.cs
- Semaphore.cs
- DataGridPagingPage.cs
- ReferenceEqualityComparer.cs
- ViewGenerator.cs
- DbDataSourceEnumerator.cs
- FixedDSBuilder.cs
- SignatureToken.cs
- MultiPageTextView.cs
- DeclarativeCatalogPart.cs
- TimeZone.cs
- InfoCardBinaryReader.cs
- AttributeCollection.cs
- NestPullup.cs
- CompoundFileStreamReference.cs
- ProgressChangedEventArgs.cs
- TdsParserStateObject.cs
- CaseInsensitiveHashCodeProvider.cs
- SafeFileMappingHandle.cs
- ConfigXmlText.cs
- EventData.cs
- CollectionViewGroupInternal.cs
- PermissionSetTriple.cs
- DataGrid.cs
- ReachSerializationUtils.cs
- XmlSchemaIdentityConstraint.cs
- DataTemplate.cs
- IsolatedStorageException.cs
- DataGridTextBoxColumn.cs
- DataGridViewRowCancelEventArgs.cs
- RoleManagerEventArgs.cs
- PropertyHelper.cs
- VirtualizingStackPanel.cs
- ObjectQueryExecutionPlan.cs
- ImageCollectionCodeDomSerializer.cs
- PageParserFilter.cs
- Application.cs
- DrawingGroupDrawingContext.cs
- FieldNameLookup.cs
- RecordManager.cs
- RSAPKCS1SignatureFormatter.cs
- Symbol.cs
- XmlLoader.cs
- MaterialGroup.cs
- BlockingCollection.cs
- XmlAtomicValue.cs
- BulletChrome.cs
- InvalidFilterCriteriaException.cs
- Accessible.cs
- HtmlEmptyTagControlBuilder.cs
- XPathChildIterator.cs
- ExcludeFromCodeCoverageAttribute.cs
- XmlSchemaGroupRef.cs
- ListViewDeleteEventArgs.cs
- MergeLocalizationDirectives.cs