Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / UpdateCompiler.cs / 1 / UpdateCompiler.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Metadata.Edm; // For the purposes of the update compiler, the member name fully describes the member // within the table entity set. // It's convenient to use 'string' to represent the member, because it allows us to // painlessly associate members of the transient extent (the table in C-Space) with // the real extent (the table in S-Space). using System.Data.Common; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Globalization; using System.Data.Common.Utils; using System.Data.SqlClient.SqlGen; using System.Data.Common.CommandTrees; using System.Data.Entity; namespace System.Data.Mapping.Update.Internal { ////// This class implements compilation of DML operation requests to some /// format (e.g. canonical query tree or T-SQL) /// internal sealed class UpdateCompiler { #region Constructors ////// Initialize an update compiler. /// /// Update context. internal UpdateCompiler(UpdateTranslator translator) { m_translator = translator; } #endregion #region Fields internal readonly UpdateTranslator m_translator; private const string s_targetVarName = "target"; #endregion ////// Builds a delete command. /// /// Value of the row being deleted. /// Context for the table containing row. ///Delete command. internal UpdateCommand BuildDeleteCommand(PropagatorResult oldRow, TableChangeProcessor processor) { // If we're deleting a row, the row must always be touched bool rowMustBeTouched = true; // Initialize DML command tree DbDeleteCommandTree commandTree = new DbDeleteCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Create delete predicate commandTree.Predicate = BuildPredicate(commandTree, oldRow, null, processor, ref rowMustBeTouched); // Set command // Initialize delete command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Delete, oldRow, null, commandTree, null); return command; } ////// Builds an update command. /// /// Old value of the row being updated. /// New value for the row being updated. /// Context for the table containing row. ///Update command. internal UpdateCommand BuildUpdateCommand(PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor) { // If we're updating a row, the row may not need to be touched (e.g., no concurrency validation required) bool rowMustBeTouched = false; // Initialize DML command tree DbUpdateCommandTree commandTree = new DbUpdateCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Create update predicate commandTree.Predicate = BuildPredicate(commandTree, oldRow, newRow, processor, ref rowMustBeTouched); // Add set clauses DictionaryoutputIdentifiers; DbExpression returning; List setClauses = new List (); foreach (DbModificationClause clause in BuildSetClauses( commandTree, newRow, processor, /* insertMode */ false, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } commandTree.InitializeSetClauses(setClauses); // Construct predicate identifying the row to modify commandTree.Predicate = BuildPredicate(commandTree, oldRow, newRow, processor, ref rowMustBeTouched); // Determine if there is nothing to do (i.e., no values to set, // no computed columns, and no concurrency validation required) if (!rowMustBeTouched && 0 == commandTree.SetClauses.Count) { return null; } // Set the returning parameters if (null != returning) { commandTree.Returning = returning; } // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Update, oldRow, newRow, commandTree, outputIdentifiers); return command; } /// /// Builds insert command. /// /// Row to insert. /// Context for the table we're inserting into. ///Insert command. internal UpdateCommand BuildInsertCommand(PropagatorResult newRow, TableChangeProcessor processor) { // Initialize DML command tree DbInsertCommandTree commandTree = new DbInsertCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Add set clauses DictionaryoutputIdentifiers; DbExpression returning; bool rowMustBeTouched = true; // for inserts, the row must always be touched List setClauses = new List (); foreach (DbModificationClause clause in BuildSetClauses(commandTree, newRow, processor, /* insertMode */ true, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } commandTree.InitializeSetClauses(setClauses); // Set the returning parameters if (null != returning) { commandTree.Returning = returning; } // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Insert, null, newRow, commandTree, outputIdentifiers); return command; } /// /// Determines column/value used to set values for a row. /// ////// The following columns are not included in the result: /// /// Command tree hosting the set parameters. /// Row containing values to set. /// Context for table. /// Determines whether key columns and 'preserve' columns are /// omitted from the list. /// Dictionary listing server generated identifiers. /// DbExpression describing result projection for server generated values. /// Indicates whether the row must be touched /// because it produces a value (e.g. computed) //////
///- Keys (if
///is set) - Values flagged 'preserve' (these are values the propagator claims are /// untouched)
///- Server generated values.
///Column value pairs. private IEnumerableBuildSetClauses(DbModificationCommandTree commandTree, PropagatorResult row, TableChangeProcessor processor, bool insertMode, out Dictionary outputIdentifiers, out DbExpression returning, ref bool rowMustBeTouched) { Dictionary setClauses = new Dictionary (); List > returningArguments = new List >(); outputIdentifiers = new Dictionary (); // Determine which flags indicate a property should be omitted from the set list. PropagatorFlags omitMask = insertMode ? PropagatorFlags.NoFlags : PropagatorFlags.Preserve | PropagatorFlags.Unknown; for (int propertyOrdinal = 0; propertyOrdinal < processor.Table.ElementType.Properties.Count; propertyOrdinal++) { EdmProperty property = processor.Table.ElementType.Properties[propertyOrdinal]; // Type members and result values are ordinally aligned PropagatorResult propertyResult = row.GetMemberValue(propertyOrdinal); if (PropagatorResult.NullIdentifier != propertyResult.Identifier) { // retrieve principal value propertyResult = propertyResult.ReplicateResultWithNewValue( m_translator.KeyManager.GetPrincipalValue(propertyResult)); } bool omitFromSetList = false; Debug.Assert(propertyResult.IsSimple); // Determine if this is a key value bool isKey = false; for (int i = 0; i < processor.KeyOrdinals.Length; i++) { if (processor.KeyOrdinals[i] == propertyOrdinal) { isKey = true; break; } } // check if this value should be omitted PropagatorFlags flags = PropagatorFlags.NoFlags; if (!insertMode && isKey) { // Keys are only set for inserts omitFromSetList = true; } else { // See if this value has been marked up with some context. If so, add the flag information // from the markup. Markup includes information about whether the property is a concurrency value, // whether it is known (it may be a property that is preserved across an update for instance) flags |= propertyResult.PropagatorFlags; } // Determine if this value is server-generated StoreGeneratedPattern genPattern = MetadataHelper.GetStoreGeneratedPattern(property); bool isServerGen = genPattern == StoreGeneratedPattern.Computed || (insertMode && genPattern == StoreGeneratedPattern.Identity); if (isServerGen) { DbPropertyExpression propertyExpression = commandTree.CreatePropertyExpression( property, commandTree.Target.Variable); returningArguments.Add(new KeyValuePair (property.Name, propertyExpression)); // check if this is a server generated identifier Int64 identifier = propertyResult.Identifier; if (PropagatorResult.NullIdentifier != identifier) { if (m_translator.KeyManager.HasPrincipals(identifier)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_GeneratedDependent(property.Name)); } outputIdentifiers.Add(identifier, property.Name); // If this property maps an identifier (in the update pipeline) it may // also be a store key. If so, the pattern had better be "Identity" // since otherwise we're dealing with a mutable key. if (genPattern != StoreGeneratedPattern.Identity && processor.IsKeyProperty(propertyOrdinal)) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.Update_NotSupportedComputedKeyColumn( EdmProviderManifest.StoreGeneratedPatternFacetName, XmlConstants.Computed, XmlConstants.Identity, property.Name, property.DeclaringType.FullName)); } } } if (PropagatorFlags.NoFlags != (flags & (omitMask))) { // column value matches "omit" pattern, therefore should not be set omitFromSetList = true; } else if (isServerGen) { // column value does not match "omit" pattern, but it is server generated // so it cannot be set omitFromSetList = true; // if the row has a modified value overridden by server gen, // it must still be touched in order to retrieve the value rowMustBeTouched = true; } // make the user is not updating an identity value if (!omitFromSetList && !insertMode && genPattern == StoreGeneratedPattern.Identity) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_ModifyingIdentityColumn( XmlConstants.Identity, property.Name, property.DeclaringType.FullName)); } if (!omitFromSetList) { setClauses.Add(property, propertyResult); } } // Construct returning projection if (0 < returningArguments.Count) { returning = commandTree.CreateNewRowExpression(returningArguments); } else { returning = null; } // Construct clauses corresponding to the set clauses List result = new List (setClauses.Count); foreach (KeyValuePair setClause in setClauses) { EdmProperty property = setClause.Key; result.Add(new DbSetClause(commandTree, GeneratePropertyExpression(commandTree, setClause.Key), GenerateValueExpression(commandTree, setClause.Key, setClause.Value))); } return result; } /// /// Determines predicate used to identify a row in a table. /// ////// Columns are included in the list when: /// /// Command tree hosting the predicate /// Values for the row being located. /// Values being updated (may be null). /// Context for the table containing the row. /// Output parameter indicating whether a row must be touched /// (whether it's being modified or not) because it contains a concurrency value //////
///- They are keys for the table
///- They are concurrency values
///Column/value pairs. private DbExpression BuildPredicate(DbModificationCommandTree commandTree, PropagatorResult referenceRow, PropagatorResult current, TableChangeProcessor processor, ref bool rowMustBeTouched) { DictionarywhereClauses = new Dictionary (); // add all concurrency tokens (note that keys are always concurrency tokens as well) int propertyOrdinal = 0; foreach (EdmProperty member in processor.Table.ElementType.Members) { // members and result values are ordinally aligned PropagatorResult expectedValue = referenceRow.GetMemberValue(propertyOrdinal); PropagatorResult newValue = null == current ? null : current.GetMemberValue(propertyOrdinal); // check if the rowMustBeTouched value should be set to true (if it isn't already // true and we've come across a concurrency value) if (!rowMustBeTouched && (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue))) { rowMustBeTouched = true; } // determine if this is a concurrency value if (!whereClauses.ContainsKey(member) && // don't add to the set clause twice (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) // tagged as concurrency value { whereClauses.Add(member, expectedValue); } propertyOrdinal++; } // Build a binary AND expression tree from the clauses DbExpression predicate = null; foreach (KeyValuePair clause in whereClauses) { DbExpression clauseExpression = GenerateEqualityExpression(commandTree, clause.Key, clause.Value); if (null == predicate) { predicate = clauseExpression; } else { predicate = commandTree.CreateAndExpression(predicate, clauseExpression); } } Debug.Assert(null != predicate, "some predicate term must exist"); return predicate; } // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the // value is null, creates an IsNull expression // Requires: all arguments are set private DbExpression GenerateEqualityExpression(DbModificationCommandTree commandTree, EdmProperty property, PropagatorResult value) { Debug.Assert(null != commandTree && null != property && null != value); DbExpression propertyExpression = GeneratePropertyExpression(commandTree, property); if (value.IsNull) { return commandTree.CreateIsNullExpression(propertyExpression); } if (!TypeSemantics.IsEqualComparable(property.TypeUsage)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_NonEquatableColumnTypeInClause( property.Name, property.DeclaringType.Name)); } return commandTree.CreateEqualsExpression(propertyExpression, GenerateValueExpression(commandTree, property, value)); } // Effects: given a property, produces a property expression // Requires: all arguments are set private static DbExpression GeneratePropertyExpression(DbModificationCommandTree commandTree, EdmProperty property) { Debug.Assert(null != commandTree && null != property); return commandTree.CreatePropertyExpression(property, commandTree.Target.Variable); } // Effects: given a propagator result, produces a constant expression describing that value. // Requires: all arguments are set, and the value must be simple (scalar) private DbExpression GenerateValueExpression(DbCommandTree commandTree, EdmProperty property, PropagatorResult value) { Debug.Assert(null != commandTree && null != value && value.IsSimple && null != property); if (value.IsNull) { return commandTree.CreateNullExpression(Helper.GetModelTypeUsage(property)); } object principalValue = m_translator.KeyManager.GetPrincipalValue(value); return commandTree.CreateConstantExpression(principalValue, Helper.GetModelTypeUsage(property)); } // Effects: returns true iff. the input propagator result has some flag defined in "flags" // Requires: input is set private static bool HasFlag(PropagatorResult input, PropagatorFlags flags) { if (null == input) { return false; } return (PropagatorFlags.NoFlags != (flags & input.PropagatorFlags)); } // Effects: initializes the target (table being modified) for the given DML command tree according // to the table managed by the processor. // Requires: all arguments set private static void SetTarget(TableChangeProcessor processor, DbModificationCommandTree commandTree) { Debug.Assert(null != processor && null != commandTree); // use a fixed var name since the command trees all have exactly one binding commandTree.Target = commandTree.CreateExpressionBinding( commandTree.CreateScanExpression(processor.Table), s_targetVarName); } } } // 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; // For the purposes of the update compiler, the member name fully describes the member // within the table entity set. // It's convenient to use 'string' to represent the member, because it allows us to // painlessly associate members of the transient extent (the table in C-Space) with // the real extent (the table in S-Space). using System.Data.Common; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Globalization; using System.Data.Common.Utils; using System.Data.SqlClient.SqlGen; using System.Data.Common.CommandTrees; using System.Data.Entity; namespace System.Data.Mapping.Update.Internal { ////// This class implements compilation of DML operation requests to some /// format (e.g. canonical query tree or T-SQL) /// internal sealed class UpdateCompiler { #region Constructors ////// Initialize an update compiler. /// /// Update context. internal UpdateCompiler(UpdateTranslator translator) { m_translator = translator; } #endregion #region Fields internal readonly UpdateTranslator m_translator; private const string s_targetVarName = "target"; #endregion ////// Builds a delete command. /// /// Value of the row being deleted. /// Context for the table containing row. ///Delete command. internal UpdateCommand BuildDeleteCommand(PropagatorResult oldRow, TableChangeProcessor processor) { // If we're deleting a row, the row must always be touched bool rowMustBeTouched = true; // Initialize DML command tree DbDeleteCommandTree commandTree = new DbDeleteCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Create delete predicate commandTree.Predicate = BuildPredicate(commandTree, oldRow, null, processor, ref rowMustBeTouched); // Set command // Initialize delete command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Delete, oldRow, null, commandTree, null); return command; } ////// Builds an update command. /// /// Old value of the row being updated. /// New value for the row being updated. /// Context for the table containing row. ///Update command. internal UpdateCommand BuildUpdateCommand(PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor) { // If we're updating a row, the row may not need to be touched (e.g., no concurrency validation required) bool rowMustBeTouched = false; // Initialize DML command tree DbUpdateCommandTree commandTree = new DbUpdateCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Create update predicate commandTree.Predicate = BuildPredicate(commandTree, oldRow, newRow, processor, ref rowMustBeTouched); // Add set clauses DictionaryoutputIdentifiers; DbExpression returning; List setClauses = new List (); foreach (DbModificationClause clause in BuildSetClauses( commandTree, newRow, processor, /* insertMode */ false, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } commandTree.InitializeSetClauses(setClauses); // Construct predicate identifying the row to modify commandTree.Predicate = BuildPredicate(commandTree, oldRow, newRow, processor, ref rowMustBeTouched); // Determine if there is nothing to do (i.e., no values to set, // no computed columns, and no concurrency validation required) if (!rowMustBeTouched && 0 == commandTree.SetClauses.Count) { return null; } // Set the returning parameters if (null != returning) { commandTree.Returning = returning; } // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Update, oldRow, newRow, commandTree, outputIdentifiers); return command; } /// /// Builds insert command. /// /// Row to insert. /// Context for the table we're inserting into. ///Insert command. internal UpdateCommand BuildInsertCommand(PropagatorResult newRow, TableChangeProcessor processor) { // Initialize DML command tree DbInsertCommandTree commandTree = new DbInsertCommandTree(m_translator.MetadataWorkspace, DataSpace.CSpace); SetTarget(processor, commandTree); // Add set clauses DictionaryoutputIdentifiers; DbExpression returning; bool rowMustBeTouched = true; // for inserts, the row must always be touched List setClauses = new List (); foreach (DbModificationClause clause in BuildSetClauses(commandTree, newRow, processor, /* insertMode */ true, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } commandTree.InitializeSetClauses(setClauses); // Set the returning parameters if (null != returning) { commandTree.Returning = returning; } // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Insert, null, newRow, commandTree, outputIdentifiers); return command; } /// /// Determines column/value used to set values for a row. /// ////// The following columns are not included in the result: /// /// Command tree hosting the set parameters. /// Row containing values to set. /// Context for table. /// Determines whether key columns and 'preserve' columns are /// omitted from the list. /// Dictionary listing server generated identifiers. /// DbExpression describing result projection for server generated values. /// Indicates whether the row must be touched /// because it produces a value (e.g. computed) //////
///- Keys (if
///is set) - Values flagged 'preserve' (these are values the propagator claims are /// untouched)
///- Server generated values.
///Column value pairs. private IEnumerableBuildSetClauses(DbModificationCommandTree commandTree, PropagatorResult row, TableChangeProcessor processor, bool insertMode, out Dictionary outputIdentifiers, out DbExpression returning, ref bool rowMustBeTouched) { Dictionary setClauses = new Dictionary (); List > returningArguments = new List >(); outputIdentifiers = new Dictionary (); // Determine which flags indicate a property should be omitted from the set list. PropagatorFlags omitMask = insertMode ? PropagatorFlags.NoFlags : PropagatorFlags.Preserve | PropagatorFlags.Unknown; for (int propertyOrdinal = 0; propertyOrdinal < processor.Table.ElementType.Properties.Count; propertyOrdinal++) { EdmProperty property = processor.Table.ElementType.Properties[propertyOrdinal]; // Type members and result values are ordinally aligned PropagatorResult propertyResult = row.GetMemberValue(propertyOrdinal); if (PropagatorResult.NullIdentifier != propertyResult.Identifier) { // retrieve principal value propertyResult = propertyResult.ReplicateResultWithNewValue( m_translator.KeyManager.GetPrincipalValue(propertyResult)); } bool omitFromSetList = false; Debug.Assert(propertyResult.IsSimple); // Determine if this is a key value bool isKey = false; for (int i = 0; i < processor.KeyOrdinals.Length; i++) { if (processor.KeyOrdinals[i] == propertyOrdinal) { isKey = true; break; } } // check if this value should be omitted PropagatorFlags flags = PropagatorFlags.NoFlags; if (!insertMode && isKey) { // Keys are only set for inserts omitFromSetList = true; } else { // See if this value has been marked up with some context. If so, add the flag information // from the markup. Markup includes information about whether the property is a concurrency value, // whether it is known (it may be a property that is preserved across an update for instance) flags |= propertyResult.PropagatorFlags; } // Determine if this value is server-generated StoreGeneratedPattern genPattern = MetadataHelper.GetStoreGeneratedPattern(property); bool isServerGen = genPattern == StoreGeneratedPattern.Computed || (insertMode && genPattern == StoreGeneratedPattern.Identity); if (isServerGen) { DbPropertyExpression propertyExpression = commandTree.CreatePropertyExpression( property, commandTree.Target.Variable); returningArguments.Add(new KeyValuePair (property.Name, propertyExpression)); // check if this is a server generated identifier Int64 identifier = propertyResult.Identifier; if (PropagatorResult.NullIdentifier != identifier) { if (m_translator.KeyManager.HasPrincipals(identifier)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_GeneratedDependent(property.Name)); } outputIdentifiers.Add(identifier, property.Name); // If this property maps an identifier (in the update pipeline) it may // also be a store key. If so, the pattern had better be "Identity" // since otherwise we're dealing with a mutable key. if (genPattern != StoreGeneratedPattern.Identity && processor.IsKeyProperty(propertyOrdinal)) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.Update_NotSupportedComputedKeyColumn( EdmProviderManifest.StoreGeneratedPatternFacetName, XmlConstants.Computed, XmlConstants.Identity, property.Name, property.DeclaringType.FullName)); } } } if (PropagatorFlags.NoFlags != (flags & (omitMask))) { // column value matches "omit" pattern, therefore should not be set omitFromSetList = true; } else if (isServerGen) { // column value does not match "omit" pattern, but it is server generated // so it cannot be set omitFromSetList = true; // if the row has a modified value overridden by server gen, // it must still be touched in order to retrieve the value rowMustBeTouched = true; } // make the user is not updating an identity value if (!omitFromSetList && !insertMode && genPattern == StoreGeneratedPattern.Identity) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_ModifyingIdentityColumn( XmlConstants.Identity, property.Name, property.DeclaringType.FullName)); } if (!omitFromSetList) { setClauses.Add(property, propertyResult); } } // Construct returning projection if (0 < returningArguments.Count) { returning = commandTree.CreateNewRowExpression(returningArguments); } else { returning = null; } // Construct clauses corresponding to the set clauses List result = new List (setClauses.Count); foreach (KeyValuePair setClause in setClauses) { EdmProperty property = setClause.Key; result.Add(new DbSetClause(commandTree, GeneratePropertyExpression(commandTree, setClause.Key), GenerateValueExpression(commandTree, setClause.Key, setClause.Value))); } return result; } /// /// Determines predicate used to identify a row in a table. /// ////// Columns are included in the list when: /// /// Command tree hosting the predicate /// Values for the row being located. /// Values being updated (may be null). /// Context for the table containing the row. /// Output parameter indicating whether a row must be touched /// (whether it's being modified or not) because it contains a concurrency value //////
///- They are keys for the table
///- They are concurrency values
///Column/value pairs. private DbExpression BuildPredicate(DbModificationCommandTree commandTree, PropagatorResult referenceRow, PropagatorResult current, TableChangeProcessor processor, ref bool rowMustBeTouched) { DictionarywhereClauses = new Dictionary (); // add all concurrency tokens (note that keys are always concurrency tokens as well) int propertyOrdinal = 0; foreach (EdmProperty member in processor.Table.ElementType.Members) { // members and result values are ordinally aligned PropagatorResult expectedValue = referenceRow.GetMemberValue(propertyOrdinal); PropagatorResult newValue = null == current ? null : current.GetMemberValue(propertyOrdinal); // check if the rowMustBeTouched value should be set to true (if it isn't already // true and we've come across a concurrency value) if (!rowMustBeTouched && (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue))) { rowMustBeTouched = true; } // determine if this is a concurrency value if (!whereClauses.ContainsKey(member) && // don't add to the set clause twice (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) || HasFlag(newValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) // tagged as concurrency value { whereClauses.Add(member, expectedValue); } propertyOrdinal++; } // Build a binary AND expression tree from the clauses DbExpression predicate = null; foreach (KeyValuePair clause in whereClauses) { DbExpression clauseExpression = GenerateEqualityExpression(commandTree, clause.Key, clause.Value); if (null == predicate) { predicate = clauseExpression; } else { predicate = commandTree.CreateAndExpression(predicate, clauseExpression); } } Debug.Assert(null != predicate, "some predicate term must exist"); return predicate; } // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the // value is null, creates an IsNull expression // Requires: all arguments are set private DbExpression GenerateEqualityExpression(DbModificationCommandTree commandTree, EdmProperty property, PropagatorResult value) { Debug.Assert(null != commandTree && null != property && null != value); DbExpression propertyExpression = GeneratePropertyExpression(commandTree, property); if (value.IsNull) { return commandTree.CreateIsNullExpression(propertyExpression); } if (!TypeSemantics.IsEqualComparable(property.TypeUsage)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_NonEquatableColumnTypeInClause( property.Name, property.DeclaringType.Name)); } return commandTree.CreateEqualsExpression(propertyExpression, GenerateValueExpression(commandTree, property, value)); } // Effects: given a property, produces a property expression // Requires: all arguments are set private static DbExpression GeneratePropertyExpression(DbModificationCommandTree commandTree, EdmProperty property) { Debug.Assert(null != commandTree && null != property); return commandTree.CreatePropertyExpression(property, commandTree.Target.Variable); } // Effects: given a propagator result, produces a constant expression describing that value. // Requires: all arguments are set, and the value must be simple (scalar) private DbExpression GenerateValueExpression(DbCommandTree commandTree, EdmProperty property, PropagatorResult value) { Debug.Assert(null != commandTree && null != value && value.IsSimple && null != property); if (value.IsNull) { return commandTree.CreateNullExpression(Helper.GetModelTypeUsage(property)); } object principalValue = m_translator.KeyManager.GetPrincipalValue(value); return commandTree.CreateConstantExpression(principalValue, Helper.GetModelTypeUsage(property)); } // Effects: returns true iff. the input propagator result has some flag defined in "flags" // Requires: input is set private static bool HasFlag(PropagatorResult input, PropagatorFlags flags) { if (null == input) { return false; } return (PropagatorFlags.NoFlags != (flags & input.PropagatorFlags)); } // Effects: initializes the target (table being modified) for the given DML command tree according // to the table managed by the processor. // Requires: all arguments set private static void SetTarget(TableChangeProcessor processor, DbModificationCommandTree commandTree) { Debug.Assert(null != processor && null != commandTree); // use a fixed var name since the command trees all have exactly one binding commandTree.Target = commandTree.CreateExpressionBinding( commandTree.CreateScanExpression(processor.Table), s_targetVarName); } } } // 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
- SHA1CryptoServiceProvider.cs
- SQLRoleProvider.cs
- DeviceContext2.cs
- PropertyInformation.cs
- ConfigurationErrorsException.cs
- AgileSafeNativeMemoryHandle.cs
- WpfSharedBamlSchemaContext.cs
- SecureConversationVersion.cs
- TypeDependencyAttribute.cs
- TextEditorSelection.cs
- SchemaElementDecl.cs
- MetadataPropertyAttribute.cs
- PointAnimation.cs
- XmlLoader.cs
- TileModeValidation.cs
- OleDbWrapper.cs
- TextOnlyOutput.cs
- PopupControlService.cs
- SchemaAttDef.cs
- DesignerRegion.cs
- MatrixUtil.cs
- OleCmdHelper.cs
- RemoteWebConfigurationHostStream.cs
- CountAggregationOperator.cs
- ArcSegment.cs
- SQLByteStorage.cs
- ExternalFile.cs
- ImageInfo.cs
- EntityDataSourceDataSelectionPanel.cs
- RijndaelManaged.cs
- Contracts.cs
- RoleProviderPrincipal.cs
- CapiSafeHandles.cs
- SmtpReplyReader.cs
- TextBoxAutoCompleteSourceConverter.cs
- DataGridViewElement.cs
- Collection.cs
- DocumentSequence.cs
- RedistVersionInfo.cs
- UnsafeNativeMethods.cs
- HttpRequest.cs
- ResourcesChangeInfo.cs
- AnimationTimeline.cs
- DataTableExtensions.cs
- MemberExpression.cs
- EventSinkActivity.cs
- XmlILCommand.cs
- DataGridViewCellContextMenuStripNeededEventArgs.cs
- WmlMobileTextWriter.cs
- XmlSchemaInfo.cs
- BeginStoryboard.cs
- GridViewDeleteEventArgs.cs
- DockingAttribute.cs
- CatalogZoneBase.cs
- TransactionTraceIdentifier.cs
- Endpoint.cs
- TextCharacters.cs
- ControlParameter.cs
- XhtmlBasicSelectionListAdapter.cs
- FilterableAttribute.cs
- SelectionItemPattern.cs
- ListViewItemSelectionChangedEvent.cs
- SiteMapProvider.cs
- DataGridViewButtonColumn.cs
- EmbeddedMailObjectsCollection.cs
- CompilerCollection.cs
- TagPrefixAttribute.cs
- RequestNavigateEventArgs.cs
- TreeNodeConverter.cs
- TraceSwitch.cs
- MultipartContentParser.cs
- InkCanvasFeedbackAdorner.cs
- AutoFocusStyle.xaml.cs
- WebBrowserNavigatedEventHandler.cs
- InfoCardRSAPKCS1KeyExchangeFormatter.cs
- DetailsViewDeleteEventArgs.cs
- TreeViewImageIndexConverter.cs
- ResourceContainer.cs
- ExclusiveCanonicalizationTransform.cs
- SecurityContext.cs
- ToolStripComboBox.cs
- ListViewUpdateEventArgs.cs
- SmtpFailedRecipientException.cs
- RadioButtonStandardAdapter.cs
- DragDeltaEventArgs.cs
- TextProperties.cs
- DataGridViewCellLinkedList.cs
- XPathNode.cs
- GroupItemAutomationPeer.cs
- FloaterBaseParagraph.cs
- DBSqlParserTableCollection.cs
- DataGridState.cs
- DataTablePropertyDescriptor.cs
- oledbconnectionstring.cs
- _NestedMultipleAsyncResult.cs
- MailWebEventProvider.cs
- Ops.cs
- RuleAttributes.cs
- ValidationErrorCollection.cs
- DrawListViewSubItemEventArgs.cs