Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / Propagator.Evaluator.cs / 1305376 / Propagator.Evaluator.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.CommandTrees; using System.Collections.Generic; using System.Diagnostics; using System.Data.Common.Utils; using System.Globalization; using System.Data.Objects; using System.Data.Metadata.Edm; using System.Data.Common; using System.Data.Entity; namespace System.Data.Mapping.Update.Internal { internal partial class Propagator { ////// Helper class supporting the evaluation of highly constrained expressions of the following /// form: /// /// P := P AND P | P OR P | NOT P | V is of type | V eq V | V /// V := P /// V := Property(V) | Constant | CASE WHEN P THEN V ... ELSE V | Row | new Instance | Null /// /// The evaluator supports SQL style ternary logic for unknown results (bool? is used, where /// null --> unknown, true --> TRUE and false --> FALSE /// ////// Assumptions: /// /// - The node and the row passed in must be type compatible. /// /// Any var refs in the node must have the same type as the input row. This is a natural /// requirement given the usage of this method in the propagator, since each propagator handler /// produces rows of the correct type for its parent. Keep in mind that every var ref in a CQT is /// bound specifically to the direct child. /// /// - Equality comparisons are CLR culture invariant. Practically, this introduces the following /// differences from SQL comparisons: /// /// - String comparisons are not collation sensitive /// - The constants we compare come from a fixed repertoire of scalar types implementing IComparable /// /// /// For the purposes of update mapping view evaluation, these assumptions are safe because we /// only support mapping of non-null constants to fields (these constants are non-null discriminators) /// and key comparisons (where the key values are replicated across a reference). /// private class Evaluator : UpdateExpressionVisitor{ #region Constructors /// /// Constructs an evaluator for evaluating expressions for the given row. /// /// Row to match /// Propagator context private Evaluator(PropagatorResult row, Propagator parent) { EntityUtil.CheckArgumentNull(row, "row"); EntityUtil.CheckArgumentNull(parent, "parent"); m_row = row; m_parent = parent; } #endregion #region Fields private PropagatorResult m_row; private Propagator m_parent; private static readonly string s_visitorName = typeof(Evaluator).FullName; #endregion #region Properties override protected string VisitorName { get { return s_visitorName; } } #endregion #region Methods ////// Utility method filtering out a set of rows given a predicate. /// /// Match criteria. /// Input rows. /// Propagator context ///Input rows matching criteria. internal static IEnumerableFilter(DbExpression predicate, IEnumerable rows, Propagator parent) { foreach (PropagatorResult row in rows) { if (EvaluatePredicate(predicate, row, parent)) { yield return row; } } } /// /// Utility method determining whether a row matches a predicate. /// ////// See Walker class for an explanation of this coding pattern. /// /// Match criteria. /// Input row. /// Propagator context ///internal static bool EvaluatePredicate(DbExpression predicate, PropagatorResult row, Propagator parent) { Evaluator evaluator = new Evaluator(row, parent); PropagatorResult expressionResult = predicate.Accept(evaluator); bool? result = ConvertResultToBool(expressionResult); // unknown --> false at base of predicate return result ?? false; } /// true if the row matches the criteria;false otherwise/// Evaluates scalar node. /// /// Sub-query returning a scalar value. /// Row to evaluate. /// Propagator context. ///Scalar result. static internal PropagatorResult Evaluate(DbExpression node, PropagatorResult row, Propagator parent) { DbExpressionVisitorevaluator = new Evaluator(row, parent); return node.Accept(evaluator); } /// /// Given an expression, converts to a (nullable) bool. Only boolean constant and null are /// supported. /// /// Result to convert ///true if true constant; false if false constant; null is null constant private static bool? ConvertResultToBool(PropagatorResult result) { Debug.Assert(null != result && result.IsSimple, "Must be a simple Boolean result"); if (result.IsNull) { return null; } else { // rely on cast exception to identify invalid cases (CQT validation should already take care of this) return (bool)result.GetSimpleValue(); } } ////// Converts a (nullable) bool to an expression. /// /// Result /// Inputs contributing to the result ///DbExpression private static PropagatorResult ConvertBoolToResult(bool? booleanValue, params PropagatorResult[] inputs) { object result; if (booleanValue.HasValue) { result = booleanValue.Value; ; } else { result = null; } PropagatorFlags flags = PropagateUnknownAndPreserveFlags(null, inputs); return PropagatorResult.CreateSimpleValue(flags, result); } #region DbExpressionVisitor implementation ////// Determines whether the argument being evaluated has a given type (declared in the IsOfOnly predicate). /// /// IsOfOnly predicate. ///True if the row being evaluated is of the requested type; false otherwise. public override PropagatorResult Visit(DbIsOfExpression predicate) { EntityUtil.CheckArgumentNull(predicate, "predicate"); if (DbExpressionKind.IsOfOnly != predicate.ExpressionKind) { throw ConstructNotSupportedException(predicate); } PropagatorResult childResult = Visit(predicate.Argument); bool result; if (childResult.IsNull) { // Null value expressions are typed, but the semantics of null are slightly different. result = false; } else { result = childResult.StructuralType.EdmEquals(predicate.OfType.EdmType); } return ConvertBoolToResult(result, childResult); } ////// Determines whether the row being evaluated has the given type (declared in the IsOf predicate). /// /// Equals predicate. ///True if the values being compared are equivalent; false otherwise. public override PropagatorResult Visit(DbComparisonExpression predicate) { EntityUtil.CheckArgumentNull(predicate, "predicate"); if (DbExpressionKind.Equals == predicate.ExpressionKind) { // Retrieve the left and right hand sides of the equality predicate. PropagatorResult leftResult = Visit(predicate.Left); PropagatorResult rightResult = Visit(predicate.Right); bool? result; if (leftResult.IsNull || rightResult.IsNull) { result = null; // unknown } else { object left = leftResult.GetSimpleValue(); object right = rightResult.GetSimpleValue(); // Perform a comparison between the sides of the equality predicate using invariant culture. // See assumptions outlined in the documentation for this class for additional information. result = ByValueEqualityComparer.Default.Equals(left, right); } return ConvertBoolToResult(result, leftResult, rightResult); } else { throw ConstructNotSupportedException(predicate); } } ////// Evaluates an 'and' expression given results of evalating its children. /// /// And predicate ///True if both child predicates are satisfied; false otherwise. public override PropagatorResult Visit(DbAndExpression predicate) { EntityUtil.CheckArgumentNull(predicate, "predicate"); PropagatorResult left = Visit(predicate.Left); PropagatorResult right = Visit(predicate.Right); bool? leftResult = ConvertResultToBool(left); bool? rightResult = ConvertResultToBool(right); bool? result; // Optimization: if either argument is false, preserved and known, return a // result that is false, preserved and known. if ((leftResult.HasValue && !leftResult.Value && PreservedAndKnown(left)) || (rightResult.HasValue && !rightResult.Value && PreservedAndKnown(right))) { return CreatePerservedAndKnownResult(false); } result = EntityUtil.ThreeValuedAnd(leftResult, rightResult); return ConvertBoolToResult(result, left, right); } ////// Evaluates an 'or' expression given results of evaluating its children. /// /// 'Or' predicate ///True if either child predicate is satisfied; false otherwise. public override PropagatorResult Visit(DbOrExpression predicate) { EntityUtil.CheckArgumentNull(predicate, "predicate"); PropagatorResult left = Visit(predicate.Left); PropagatorResult right = Visit(predicate.Right); bool? leftResult = ConvertResultToBool(left); bool? rightResult = ConvertResultToBool(right); bool? result; // Optimization: if either argument is true, preserved and known, return a // result that is true, preserved and known. if ((leftResult.HasValue && leftResult.Value && PreservedAndKnown(left)) || (rightResult.HasValue && rightResult.Value && PreservedAndKnown(right))) { return CreatePerservedAndKnownResult(true); } result = EntityUtil.ThreeValuedOr(leftResult, rightResult); return ConvertBoolToResult(result, left, right); } private static PropagatorResult CreatePerservedAndKnownResult(object value) { // Known is the default (no explicit flag required) return PropagatorResult.CreateSimpleValue(PropagatorFlags.Preserve, value); } private static bool PreservedAndKnown(PropagatorResult result) { // Check that the preserve flag is set, and the unknown flag is not set return PropagatorFlags.Preserve == (result.PropagatorFlags & (PropagatorFlags.Preserve | PropagatorFlags.Unknown)); } ////// Evalutes a 'not' expression given results /// /// 'Not' predicate ///True of the argument to the 'not' predicate evaluator to false; false otherwise public override PropagatorResult Visit(DbNotExpression predicate) { EntityUtil.CheckArgumentNull(predicate, "predicate"); PropagatorResult child = Visit(predicate.Argument); bool? childResult = ConvertResultToBool(child); bool? result = EntityUtil.ThreeValuedNot(childResult); return ConvertBoolToResult(result, child); } ////// Returns the result of evaluating a case expression. /// /// Case expression node. ///Result of evaluating case expression over the input row for this visitor. public override PropagatorResult Visit(DbCaseExpression node) { Debug.Assert(null != node, "node is not visited when null"); int match = -1; int statementOrdinal = 0; Listinputs = new List (); foreach (DbExpression when in node.When) { PropagatorResult whenResult = Visit(when); inputs.Add(whenResult); bool matches = ConvertResultToBool(whenResult) ?? false; // ternary logic resolution if (matches) { match = statementOrdinal; break; } statementOrdinal++; } PropagatorResult matchResult; if (-1 == match) { matchResult = Visit(node.Else); } else { matchResult = Visit(node.Then[match]); } inputs.Add(matchResult); // Clone the result to avoid modifying expressions that may be used elsewhere // (design invariant: only set markup for expressions you create) PropagatorFlags resultFlags = PropagateUnknownAndPreserveFlags(matchResult, inputs); PropagatorResult result = matchResult.ReplicateResultWithNewFlags(resultFlags); return result; } /// /// Evaluates a var ref. In practice, this corresponds to the input row for the visitor (the row is /// a member of the referenced input for a projection or filter). /// We assert that types are consistent here. /// /// Var ref expression node ///Input row for the visitor. public override PropagatorResult Visit(DbVariableReferenceExpression node) { Debug.Assert(null != node, "node is not visited when null"); return m_row; } ////// Evaluates a property expression given the result of evaluating the property's instance. /// /// Property expression node. ///DbExpression resulting from the evaluation of property. public override PropagatorResult Visit(DbPropertyExpression node) { Debug.Assert(null != node, "node is not visited when null"); // Retrieve the result of evaluating the instance for the property. PropagatorResult instance = Visit(node.Instance); PropagatorResult result; if (instance.IsNull) { result = PropagatorResult.CreateSimpleValue(instance.PropagatorFlags, null); } else { // find member result = instance.GetMemberValue(node.Property); } // We do not markup the result since the property value already contains the necessary context // (determined at record extraction time) return result; } ////// Evaluates a constant expression (trivial: the result is the constant expression) /// /// Constant expression node. ///Constant expression public override PropagatorResult Visit(DbConstantExpression node) { Debug.Assert(null != node, "node is not visited when null"); // Flag the expression as 'preserve', since constants (by definition) cannot vary PropagatorResult result = PropagatorResult.CreateSimpleValue(PropagatorFlags.Preserve, node.Value); return result; } ////// Evaluates a ref key expression based on the result of evaluating the argument to the ref. /// /// Ref key expression node. ///The structural key of the ref as a new instance (record). public override PropagatorResult Visit(DbRefKeyExpression node) { Debug.Assert(null != node, "node is not visited when null"); // Retrieve the result of evaluating the child argument. PropagatorResult argument = Visit(node.Argument); // Return the argument directly (propagator results treat refs as standard structures) return argument; } ////// Evaluates a null expression (trivial: the result is the null expression) /// /// Null expression node. ///Null expression public override PropagatorResult Visit(DbNullExpression node) { Debug.Assert(null != node, "node is not visited when null"); // Flag the expression as 'preserve', since nulls (by definition) cannot vary PropagatorResult result = PropagatorResult.CreateSimpleValue(PropagatorFlags.Preserve, null); return result; } ////// Evaluates treat expression given a result for the argument to the treat. /// /// Treat expression ///Null if the argument is of the given type, the argument otherwise public override PropagatorResult Visit(DbTreatExpression node) { Debug.Assert(null != node, "node is not visited when null"); PropagatorResult childResult = Visit(node.Argument); TypeUsage nodeType = node.ResultType; if (MetadataHelper.IsSuperTypeOf(nodeType.EdmType, childResult.StructuralType)) { // Doing an up cast is not required because all property/ordinal // accesses are unaffected for more derived types (derived members // are appended) return childResult; } // "Treat" where the result does not implement the given type results in a null // result PropagatorResult result = PropagatorResult.CreateSimpleValue(childResult.PropagatorFlags, null); return result; } ////// Casts argument to expression. /// /// Cast expression node ///Result of casting argument public override PropagatorResult Visit(DbCastExpression node) { Debug.Assert(null != node, "node is not visited when null"); PropagatorResult childResult = Visit(node.Argument); TypeUsage nodeType = node.ResultType; if (!childResult.IsSimple || BuiltInTypeKind.PrimitiveType != nodeType.EdmType.BuiltInTypeKind) { throw EntityUtil.NotSupported(Strings.Update_UnsupportedCastArgument(nodeType.EdmType.Name)); } object resultValue; if (childResult.IsNull) { resultValue = null; } else { try { resultValue = Cast(childResult.GetSimpleValue(), ((PrimitiveType)nodeType.EdmType).ClrEquivalentType); } catch { Debug.Fail("view generator failed to validate cast in update mapping view"); throw; } } PropagatorResult result = childResult.ReplicateResultWithNewValue(resultValue); return result; } ////// Casts an object instance to the specified model type. /// /// Value to cast /// clr type to which the value is casted to ///Cast value private static object Cast(object value, Type clrPrimitiveType) { IFormatProvider formatProvider = CultureInfo.InvariantCulture; if (null == value || value.GetType() == clrPrimitiveType) { return value; } else { //Convert is not handling DateTime to DateTimeOffset conversion if ( (value is DateTime) && (clrPrimitiveType == typeof(DateTimeOffset))) { return new DateTimeOffset(((DateTime)value).Ticks, TimeSpan.Zero); } else { return Convert.ChangeType(value, clrPrimitiveType, formatProvider); } } } ////// Evaluate a null expression. /// /// Is null expression ///A boolean expression describing the result of evaluating the Is Null predicate public override PropagatorResult Visit(DbIsNullExpression node) { Debug.Assert(null != node, "node is not visited when null"); PropagatorResult argumentResult = Visit(node.Argument); bool result = argumentResult.IsNull; return ConvertBoolToResult(result, argumentResult); } #endregion ////// Supports propagation of preserve and unknown values when evaluating expressions. If any input /// to an expression is marked as unknown, the same is true of the result of evaluating /// that expression. If all inputs to an expression are marked 'preserve', then the result is also /// marked preserve. /// /// Result to markup /// Expressions contributing to the result ///Marked up result. private static PropagatorFlags PropagateUnknownAndPreserveFlags(PropagatorResult result, IEnumerableinputs) { bool unknown = false; bool preserve = true; bool noInputs = true; // aggregate all flags on the inputs foreach (PropagatorResult input in inputs) { noInputs = false; PropagatorFlags inputFlags = input.PropagatorFlags; if (PropagatorFlags.NoFlags != (PropagatorFlags.Unknown & inputFlags)) { unknown = true; } if (PropagatorFlags.NoFlags == (PropagatorFlags.Preserve & inputFlags)) { preserve = false; } } if (noInputs) { preserve = false; } if (null != result) { // Merge with existing flags PropagatorFlags flags = result.PropagatorFlags; if (unknown) { flags |= PropagatorFlags.Unknown; } if (!preserve) { flags &= ~PropagatorFlags.Preserve; } return flags; } else { // if there is no input result, create new markup from scratch PropagatorFlags flags = PropagatorFlags.NoFlags; if (unknown) { flags |= PropagatorFlags.Unknown; } if (preserve) { flags |= PropagatorFlags.Preserve; } return flags; } } #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
- ContentType.cs
- EnumConverter.cs
- AddressHeaderCollection.cs
- XmlSecureResolver.cs
- RectAnimationClockResource.cs
- ProvideValueServiceProvider.cs
- CompositeActivityTypeDescriptor.cs
- DocumentCollection.cs
- ReferenceConverter.cs
- RadialGradientBrush.cs
- ToolStripComboBox.cs
- SocketException.cs
- Enumerable.cs
- Block.cs
- DataShape.cs
- FillBehavior.cs
- WebPartConnectionsConfigureVerb.cs
- ValidationVisibilityAttribute.cs
- InvalidCastException.cs
- PasswordRecovery.cs
- Page.cs
- DataColumnChangeEvent.cs
- DuplicateWaitObjectException.cs
- BuildManagerHost.cs
- PassportPrincipal.cs
- recordstatefactory.cs
- StrongNameMembershipCondition.cs
- PersonalizationStateQuery.cs
- CacheMemory.cs
- PassportAuthenticationModule.cs
- SettingsPropertyNotFoundException.cs
- CommandSet.cs
- HtmlInputText.cs
- ScrollItemPatternIdentifiers.cs
- IdentityReference.cs
- WebPartsPersonalization.cs
- XPathNode.cs
- ScopelessEnumAttribute.cs
- HTMLTextWriter.cs
- XPathPatternBuilder.cs
- _SpnDictionary.cs
- SqlFormatter.cs
- AppendHelper.cs
- Int32KeyFrameCollection.cs
- FixedSOMContainer.cs
- XPathPatternParser.cs
- SequenceFullException.cs
- OciLobLocator.cs
- BaseCodeDomTreeGenerator.cs
- DataGridViewCellMouseEventArgs.cs
- RowCache.cs
- DeviceContext.cs
- FilteredAttributeCollection.cs
- EnumValidator.cs
- List.cs
- EntityContainer.cs
- SecurityHeaderLayout.cs
- Char.cs
- Stopwatch.cs
- ExecutionScope.cs
- TableHeaderCell.cs
- SettingsContext.cs
- ExtentKey.cs
- SQlBooleanStorage.cs
- SafeArrayTypeMismatchException.cs
- ComponentResourceKeyConverter.cs
- HebrewCalendar.cs
- Parser.cs
- TextBlock.cs
- IDQuery.cs
- HtmlTextArea.cs
- ColumnMapProcessor.cs
- PhysicalAddress.cs
- ToolTipAutomationPeer.cs
- HttpCapabilitiesSectionHandler.cs
- Executor.cs
- CodePropertyReferenceExpression.cs
- XmlDictionaryWriter.cs
- EventHandlerList.cs
- RequestSecurityToken.cs
- Statements.cs
- AutomationElementCollection.cs
- Msmq4SubqueuePoisonHandler.cs
- ChannelParameterCollection.cs
- ReadWriteObjectLock.cs
- Window.cs
- ObjectStateEntryDbDataRecord.cs
- HtmlControl.cs
- EditorPartCollection.cs
- GridErrorDlg.cs
- DataGridViewImageCell.cs
- ContentOperations.cs
- DataGridViewColumnStateChangedEventArgs.cs
- VBCodeProvider.cs
- IDQuery.cs
- FormViewCommandEventArgs.cs
- HtmlHistory.cs
- WindowsTokenRoleProvider.cs
- ContextConfiguration.cs
- XmlNavigatorStack.cs