FunctionImportMapping.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Mapping / FunctionImportMapping.cs / 2 / FunctionImportMapping.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Metadata.Edm;
using System.Collections.Generic; 
using System.Data.Common;
using System.Linq;
using System.Xml;
using System.Data.Common.Utils; 
using System.Data.Entity;
using OM = System.Collections.ObjectModel; 
using System.Globalization; 
using System.Diagnostics;
using System.Collections; 
using System.Data.Common.Utils.Boolean;
using System.Xml.XPath;
namespace System.Data.Mapping
{ 
    /// 
    /// Represents a mapping from a model FunctionImport to a store 
    /// non-composable Function. 
    /// 
    internal sealed class FunctionImportMapping 
    {
        internal FunctionImportMapping(EdmFunction targetFunction, EdmFunction functionImport,
            IEnumerable entityTypeMappings, ItemCollection itemCollection)
        { 
            this.TargetFunction = EntityUtil.CheckArgumentNull(targetFunction, "targetFunction");
            this.FunctionImport = EntityUtil.CheckArgumentNull(functionImport, "functionImport"); 
            EntityUtil.CheckArgumentNull(itemCollection, "itemCollection"); 

            // collect all mapped entity types 
            this.MappedEntityTypes = entityTypeMappings
                .SelectMany(mapping => mapping.GetMappedEntityTypes(itemCollection))
                .Distinct()
                .ToList() 
                .AsReadOnly();
 
            // collect all discriminator columns 
            this.DiscriminatorColumns = entityTypeMappings
                .SelectMany(mapping => mapping.GetDiscriminatorColumns()) 
                .Distinct()
                .ToList()
                .AsReadOnly();
 
            this.EntityTypeLineInfos = new KeyToListMap(EqualityComparer.Default);
            this.IsTypeOfLineInfos = new KeyToListMap(EqualityComparer.Default); 
 
            // normalize the type mappings
            var normalizedEntityTypeMappings = new List(); 
            foreach (var entityTypeMapping in entityTypeMappings)
            {
                // remember LineInfos for error reporting
                foreach (var entityType in entityTypeMapping.EntityTypes) 
                {
                    this.EntityTypeLineInfos.Add(entityType, entityTypeMapping.LineInfo); 
                } 
                foreach (var isTypeOf in entityTypeMapping.IsOfTypeEntityTypes)
                { 
                    this.IsTypeOfLineInfos.Add(isTypeOf, entityTypeMapping.LineInfo);
                }

                // create map from column name to condition 
                var columnMap = entityTypeMapping.Conditions.ToDictionary(
                    condition => condition.ColumnName, 
                    condition => condition); 

                // align conditions with discriminator columns 
                var columnMappings = new List(this.DiscriminatorColumns.Count);
                for (int i = 0; i < this.DiscriminatorColumns.Count; i++)
                {
                    string discriminatorColumn = this.DiscriminatorColumns[i]; 
                    FunctionImportEntityTypeMappingCondition mappingCondition;
                    if (columnMap.TryGetValue(discriminatorColumn, out mappingCondition)) 
                    { 
                        columnMappings.Add(mappingCondition);
                    } 
                    else
                    {
                        // null indicates the value for this discriminator doesn't matter
                        columnMappings.Add(null); 
                    }
                } 
 
                // create bit map for implied entity types
                bool[] impliedEntityTypesBitMap = new bool[this.MappedEntityTypes.Count]; 
                var impliedEntityTypesSet = new Set(entityTypeMapping.GetMappedEntityTypes(itemCollection));
                for (int i = 0; i < this.MappedEntityTypes.Count; i++)
                {
                    impliedEntityTypesBitMap[i] = impliedEntityTypesSet.Contains(this.MappedEntityTypes[i]); 
                }
 
                // construct normalized mapping 
                normalizedEntityTypeMappings.Add(new FunctionImportNormalizedEntityTypeMapping(this,
                    columnMappings, new BitArray(impliedEntityTypesBitMap))); 
            }

            this.NormalizedEntityTypeMappings = new OM.ReadOnlyCollection(
                normalizedEntityTypeMappings); 
        }
 
        ///  
        /// Gets store function (or target of the mapping)
        ///  
        internal readonly EdmFunction TargetFunction;

        /// 
        /// Gets model function (or source of the mapping) 
        /// 
        internal readonly EdmFunction FunctionImport; 
 
        /// 
        /// Gets all types in scope for this mapping. 
        /// 
        internal readonly OM.ReadOnlyCollection MappedEntityTypes;

        ///  
        /// Gets a list of all discriminator columns used in this mapping.
        ///  
        internal readonly OM.ReadOnlyCollection DiscriminatorColumns; 

        ///  
        /// Gets normalized representation of all EntityTypeMapping fragments for this
        /// function import mapping.
        /// 
        internal readonly OM.ReadOnlyCollection NormalizedEntityTypeMappings; 

        ///  
        /// Gets line infos for entity type mappings. 
        /// 
        internal readonly KeyToListMap EntityTypeLineInfos; 

        /// 
        /// Gets line infos for IsTypeOf mappings for entity types.
        ///  
        internal readonly KeyToListMap IsTypeOfLineInfos;
 
        ///  
        /// Given discriminator values (ordinally aligned with DiscriminatorColumns), determines
        /// the entity type to return. Throws a CommandExecutionException if the type is ambiguous. 
        /// 
        internal EntityType Discriminate(object[] discriminatorValues)
        {
            // initialize matching types bit map 
            BitArray typeCandidates = new BitArray(this.MappedEntityTypes.Count, true);
 
            foreach (var typeMapping in this.NormalizedEntityTypeMappings) 
            {
                // check if this type mapping is matched 
                bool matches = true;
                var columnConditions = typeMapping.ColumnConditions;
                for (int i = 0; i < columnConditions.Count; i++)
                { 
                    if (null != columnConditions[i] && // this discriminator doesn't matter for the given condition
                        !columnConditions[i].ColumnValueMatchesCondition(discriminatorValues[i])) 
                    { 
                        matches = false;
                        break; 
                    }
                }

                if (matches) 
                {
                    // if the type condition is met, narrow the set of type candidates 
                    typeCandidates = typeCandidates.And(typeMapping.ImpliedEntityTypes); 
                }
                else 
                {
                    // if the type condition fails, all implied types are eliminated
                    // (the type mapping fragment is a co-implication, so a type is no longer
                    // a candidate if any condition referring to it is false) 
                    typeCandidates = typeCandidates.And(typeMapping.ComplementImpliedEntityTypes);
                } 
            } 

            // find matching type condition 
            EntityType entityType = null;
            for (int i = 0; i < typeCandidates.Length; i++)
            {
                if (typeCandidates[i]) 
                {
                    if (null != entityType) 
                    { 
                        throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
                    } 
                    entityType = this.MappedEntityTypes[i];
                }
            }
 
            // if there is no match, raise an exception
            if (null == entityType) 
            { 
                throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
            } 

            return entityType;
        }
 
        /// 
        /// Determines which explicitly mapped types in the function import mapping cannot be generated. 
        /// For IsTypeOf declarations, reports if no type in hierarchy can be produced. 
        ///
        /// Works by: 
        ///
        /// - Converting type mapping conditions into vertices
        /// - Checking that some assignment satisfies
        ///  
        internal void GetUnreachableTypes(EdmItemCollection itemCollection,
            out KeyToListMap unreachableEntityTypes, 
            out KeyToListMap unreachableIsTypeOfs) 
        {
            // Contains, for each DiscriminatorColumn, a domain variable where the domain values are 
            // integers representing the ordinal within discriminatorDomains
            DomainVariable[] variables = ConstructDomainVariables();

            // Convert type mapping conditions to decision diagram vertices 
            var converter = new DomainConstraintConversionContext();
            Vertex[] mappingConditions = ConvertMappingConditionsToVertices(converter, variables); 
 
            // Find reachable types
            Set reachableTypes = FindReachableTypes(converter, mappingConditions); 

            CollectUnreachableTypes(itemCollection, reachableTypes, out unreachableEntityTypes, out unreachableIsTypeOfs);
        }
 
        /// 
        /// Determines the expected shape of store results. We expect a column for every property 
        /// of the mapped type (or types) and a column for every discriminator column. We make no 
        /// assumptions about the order of columns: the provider is expected to determine appropriate
        /// types by looking at the names of the result columns, not the order of columns, which is 
        /// different from the typical handling of row types in the EF.
        /// 
        /// 
        /// Requires that the given function import mapping refers to a Collection(Entity) CSDL 
        /// function.
        ///  
        /// Row type. 
        internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace)
        { 
            // Collect all columns as name-type pairs.
            Dictionary columns = new Dictionary();

            // Figure out which entity types we expect to yield from the function. 
            IEnumerable entityTypes;
            if (0 == this.NormalizedEntityTypeMappings.Count) 
            { 
                // No explicit type mappings; just use the base entity type.
                EntityType entityType; 
                MetadataHelper.TryGetFunctionImportReturnEntityType(this.FunctionImport, out entityType);
                Debug.Assert(null != entityType, "this method must be called only for entity reader function imports");
                entityTypes = new EntityType[] { entityType };
            } 
            else
            { 
                // Types are explicitly mapped. 
                entityTypes = this.MappedEntityTypes;
            } 

            // Gather columns corresponding to all entity properties.
            foreach (EntityType entityType in entityTypes)
            { 
                foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(entityType))
                { 
                    // NOTE: if a complex type is encountered, the column map generator will 
                    // throw. For now, we just let them through.
 
                    // We expect to see each property multiple times, so we use .item rather than
                    // .Add.
                    columns[property.Name] = property.TypeUsage;
                } 
            }
 
            // Gather discriminator columns. 
            foreach (string discriminatorColumn in this.DiscriminatorColumns)
            { 
                if (!columns.ContainsKey(discriminatorColumn))
                {
                    //
 

 
 

 
                    TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false);
                    columns.Add(discriminatorColumn, type);
                }
            } 

            // Expected type is a collection of rows 
            RowType rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); 
            TypeUsage result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType)));
            return result; 
        }

        /// 
        /// Determines which types are produced by this mapping 
        /// 
        private Set FindReachableTypes(DomainConstraintConversionContext converter, 
            Vertex[] mappingConditions) 
        {
            Set reachableTypes = new Set(); 

            // for each entity type, create a candidate function that evaluates to true given
            // discriminator assignments iff. all of that type's conditions evaluate to true
            // and its negative conditions evaluate to false 
            Vertex[] candidateFunctions = new Vertex[this.MappedEntityTypes.Count];
            for (int i = 0; i < candidateFunctions.Length; i++) 
            { 
                // seed the candidate function conjunction with 'true'
                Vertex candidateFunction = Vertex.One; 
                for (int j = 0; j < this.NormalizedEntityTypeMappings.Count; j++)
                {
                    var entityTypeMapping = this.NormalizedEntityTypeMappings[j];
 
                    // determine if this mapping is a positive or negative case for the current type
                    if (entityTypeMapping.ImpliedEntityTypes[i]) 
                    { 
                        candidateFunction = converter.Solver.And(candidateFunction, mappingConditions[j]);
                    } 
                    else
                    {
                        candidateFunction = converter.Solver.And(candidateFunction, converter.Solver.Not(mappingConditions[j]));
                    } 
                }
                candidateFunctions[i] = candidateFunction; 
            } 

            // for each type, make sure there is some assignment that resolves to only that type 
            for (int i = 0; i < candidateFunctions.Length; i++)
            {
                // create a function that evaluates to true iff. the current candidate function is true
                // and every other candidate function is false 
                Vertex isExactlyThisTypeCondition = converter.Solver.And(
                    candidateFunctions.Select((typeCondition, ordinal) => ordinal == i ? 
                        typeCondition : 
                        converter.Solver.Not(typeCondition)));
 
                // if the above conjunction is satisfiable, it means some row configuration exists
                // producing the type
                if (!isExactlyThisTypeCondition.IsZero())
                { 
                    reachableTypes.Add(this.MappedEntityTypes[i]);
                } 
            } 
            return reachableTypes;
        } 

        private void CollectUnreachableTypes(EdmItemCollection itemCollection, Set reachableTypes, out KeyToListMap entityTypes, out KeyToListMap isTypeOfEntityTypes)
        {
            // Collect line infos for types in violation 
            entityTypes = new KeyToListMap(EqualityComparer.Default);
            isTypeOfEntityTypes = new KeyToListMap(EqualityComparer.Default); 
 
            if (reachableTypes.Count == this.MappedEntityTypes.Count)
            { 
                // All types are reachable; nothing to check
                return;
            }
 
            // Find IsTypeOf mappings where no type in hierarchy can generate a row
            foreach (var isTypeOf in this.IsTypeOfLineInfos.Keys) 
            { 
                if (!MetadataHelper.GetTypeAndSubtypesOf(isTypeOf, itemCollection, false)
                    .Cast() 
                    .Intersect(reachableTypes)
                    .Any())
                {
                    // no type in the hierarchy is reachable... 
                    isTypeOfEntityTypes.AddRange(isTypeOf, this.IsTypeOfLineInfos.EnumerateValues(isTypeOf));
                } 
            } 

            // Find explicit types not generating a value 
            foreach (var entityType in this.EntityTypeLineInfos.Keys)
            {
                if (!reachableTypes.Contains(entityType))
                { 
                    entityTypes.AddRange(entityType, this.EntityTypeLineInfos.EnumerateValues(entityType));
                } 
            } 
        }
 
        private DomainVariable[] ConstructDomainVariables()
        {
            // determine domain for each discriminator column, including "other" and "null" placeholders
            var discriminatorDomains = new Set[this.DiscriminatorColumns.Count]; 
            for (int i = 0; i < discriminatorDomains.Length; i++)
            { 
                discriminatorDomains[i] = new Set(); 
                discriminatorDomains[i].Add(ValueCondition.IsOther);
                discriminatorDomains[i].Add(ValueCondition.IsNull); 
            }

            // collect all domain values
            foreach (var typeMapping in this.NormalizedEntityTypeMappings) 
            {
                for (int i = 0; i < this.DiscriminatorColumns.Count; i++) 
                { 
                    var discriminatorValue = typeMapping.ColumnConditions[i];
                    if (null != discriminatorValue && 
                        !discriminatorValue.ConditionValue.IsNotNullCondition) // NotNull is a special range (everything but IsNull)
                    {
                        discriminatorDomains[i].Add(discriminatorValue.ConditionValue);
                    } 
                }
            } 
 
            var discriminatorVariables = new DomainVariable[discriminatorDomains.Length];
            for (int i = 0; i < discriminatorVariables.Length; i++) 
            {
                // domain variable is identified by the column name and takes all collected domain values
                discriminatorVariables[i] = new DomainVariable(this.DiscriminatorColumns[i],
                    discriminatorDomains[i].MakeReadOnly()); 
            }
 
            return discriminatorVariables; 
        }
 
        private Vertex[] ConvertMappingConditionsToVertices(ConversionContext> converter,
            DomainVariable[] variables)
        {
            Vertex[] conditions = new Vertex[this.NormalizedEntityTypeMappings.Count]; 
            for (int i = 0; i < conditions.Length; i++)
            { 
                var typeMapping = this.NormalizedEntityTypeMappings[i]; 

                // create conjunction representing the condition 
                Vertex condition = Vertex.One;
                for (int j = 0; j < this.DiscriminatorColumns.Count; j++)
                {
                    var columnCondition = typeMapping.ColumnConditions[j]; 
                    if (null != columnCondition)
                    { 
                        var conditionValue = columnCondition.ConditionValue; 
                        if (conditionValue.IsNotNullCondition)
                        { 
                            // the 'not null' condition is not actually part of the domain (since it
                            // covers other elements), so create a Not(value in {null}) condition
                            var isNull = new TermExpr>(
                                new DomainConstraint(variables[j], ValueCondition.IsNull)); 
                            Vertex isNullVertex = converter.TranslateTermToVertex(isNull);
                            condition = converter.Solver.And(condition, converter.Solver.Not(isNullVertex)); 
                        } 
                        else
                        { 
                            var hasValue = new TermExpr>(
                                new DomainConstraint(variables[j], conditionValue));
                            condition = converter.Solver.And(condition, converter.TranslateTermToVertex(hasValue));
                        } 
                    }
                } 
                conditions[i] = condition; 
            }
            return conditions; 
        }
    }

    internal sealed class FunctionImportNormalizedEntityTypeMapping 
    {
        internal FunctionImportNormalizedEntityTypeMapping(FunctionImportMapping parent, 
            List columnConditions, BitArray impliedEntityTypes) 
        {
            // validate arguments 
            EntityUtil.CheckArgumentNull(parent, "parent");
            EntityUtil.CheckArgumentNull(columnConditions, "discriminatorValues");
            EntityUtil.CheckArgumentNull(impliedEntityTypes, "impliedEntityTypes");
 
            Debug.Assert(columnConditions.Count == parent.DiscriminatorColumns.Count,
                "discriminator values must be ordinally aligned with discriminator columns"); 
            Debug.Assert(impliedEntityTypes.Count == parent.MappedEntityTypes.Count, 
                "implied entity types must be ordinally aligned with mapped entity types");
 
            this.ColumnConditions = new OM.ReadOnlyCollection(columnConditions.ToList());
            this.ImpliedEntityTypes = impliedEntityTypes;
            this.ComplementImpliedEntityTypes = (new BitArray(this.ImpliedEntityTypes)).Not();
        } 

        ///  
        /// Gets discriminator values aligned with DiscriminatorColumns of the parent FunctionImportMapping. 
        /// A null ValueCondition indicates 'anything goes'.
        ///  
        internal readonly OM.ReadOnlyCollection ColumnConditions;

        /// 
        /// Gets bit array with 'true' indicating the corresponding MappedEntityType of the parent 
        /// FunctionImportMapping is implied by this fragment.
        ///  
        internal readonly BitArray ImpliedEntityTypes; 

        ///  
        /// Gets the complement of the ImpliedEntityTypes BitArray.
        /// 
        internal readonly BitArray ComplementImpliedEntityTypes;
 
        public override string ToString()
        { 
            return String.Format(CultureInfo.InvariantCulture, "Values={0}, Types={1}", 
                StringUtil.ToCommaSeparatedString(this.ColumnConditions), StringUtil.ToCommaSeparatedString(this.ImpliedEntityTypes));
        } 
    }

    internal sealed class FunctionImportEntityTypeMapping
    { 
        internal FunctionImportEntityTypeMapping(IEnumerable isOfTypeEntityTypes,
            IEnumerable entityTypes, IEnumerable conditions, 
            IXmlLineInfo lineInfo) 
        {
            this.IsOfTypeEntityTypes = new OM.ReadOnlyCollection( 
                EntityUtil.CheckArgumentNull(isOfTypeEntityTypes, "isOfTypeEntityTypes").ToList());
            this.EntityTypes = new OM.ReadOnlyCollection(
                EntityUtil.CheckArgumentNull(entityTypes, "entityTypes").ToList());
            this.Conditions = new OM.ReadOnlyCollection( 
                EntityUtil.CheckArgumentNull(conditions, "conditions").ToList());
            this.LineInfo = lineInfo; 
        } 

        internal readonly OM.ReadOnlyCollection Conditions; 
        internal readonly OM.ReadOnlyCollection EntityTypes;
        internal readonly OM.ReadOnlyCollection IsOfTypeEntityTypes;
        internal readonly IXmlLineInfo LineInfo;
 
        /// 
        /// Gets all (concrete) entity types implied by this type mapping. 
        ///  
        internal IEnumerable GetMappedEntityTypes(ItemCollection itemCollection)
        { 
            const bool includeAbstractTypes = false;
            return this.EntityTypes.Concat(
                this.IsOfTypeEntityTypes.SelectMany(entityType =>
                    MetadataHelper.GetTypeAndSubtypesOf(entityType, itemCollection, includeAbstractTypes) 
                    .Cast()));
        } 
 
        internal IEnumerable GetDiscriminatorColumns()
        { 
            return this.Conditions.Select(condition => condition.ColumnName);
        }
    }
 
    internal abstract class FunctionImportEntityTypeMappingCondition
    { 
        protected FunctionImportEntityTypeMappingCondition(string columnName) 
        {
            this.ColumnName = EntityUtil.CheckArgumentNull(columnName, "columnName"); 
        }

        internal abstract ValueCondition ConditionValue { get; }
 
        internal readonly string ColumnName;
 
        internal abstract bool ColumnValueMatchesCondition(object columnValue); 

        public override string ToString() 
        {
            return this.ConditionValue.ToString();
        }
    } 

    internal sealed class FunctionImportEntityTypeMappingConditionValue : FunctionImportEntityTypeMappingCondition 
    { 
        internal FunctionImportEntityTypeMappingConditionValue(string columnName, XPathNavigator columnValue)
            : base(columnName) 
        {
            this._xPathValue = EntityUtil.CheckArgumentNull(columnValue, "columnValue");
            this._convertedValues = new Memoizer(this.GetConditionValue, null);
        } 

        private readonly XPathNavigator _xPathValue; 
        private readonly Memoizer _convertedValues; 

        internal override ValueCondition ConditionValue 
        {
            get { return new ValueCondition(_xPathValue.Value); }
        }
 
        internal override bool ColumnValueMatchesCondition(object columnValue)
        { 
            if (null == columnValue || Convert.IsDBNull(columnValue)) 
            {
                // only FunctionImportEntityTypeMappingConditionIsNull can match a null 
                // column value
                return false;
            }
 
            Type columnValueType = columnValue.GetType();
 
            // check if we've interpreted this column type yet 
            object conditionValue = _convertedValues.Evaluate(columnValueType);
            return CdpEqualityComparer.DefaultEqualityComparer.Equals(columnValue, conditionValue); 
        }

        private object GetConditionValue(Type columnValueType)
        { 
            object conditionValue;
 
            // check that the type is supported 
            PrimitiveType primitiveType;
            if (!ClrProviderManifest.Instance.TryGetPrimitiveType(columnValueType, out primitiveType) || 
                !StorageMappingItemLoader.IsTypeSupportedForCondition(primitiveType.PrimitiveTypeKind))
            {
                throw EntityUtil.CommandExecution(Strings.Mapping_FunctionImport_UnsupportedType(
                    this.ColumnName, columnValueType.FullName)); 
            }
 
            try 
            {
                conditionValue = _xPathValue.ValueAs(columnValueType); 
            }
            catch (FormatException)
            {
                throw EntityUtil.CommandExecution(Strings.Mapping_FunctionImport_ConditionValueTypeMismatch( 
                    StorageMslConstructs.FunctionImportMappingElement, this.ColumnName, columnValueType.FullName));
            } 
 
            return conditionValue;
        } 
    }

    internal sealed class FunctionImportEntityTypeMappingConditionIsNull : FunctionImportEntityTypeMappingCondition
    { 
        internal FunctionImportEntityTypeMappingConditionIsNull(string columnName, bool isNull)
            : base(columnName) 
        { 
            this.IsNull = isNull;
        } 

        internal readonly bool IsNull;

        internal override ValueCondition ConditionValue 
        {
            get { return IsNull ? ValueCondition.IsNull : ValueCondition.IsNotNull; } 
        } 

        internal override bool ColumnValueMatchesCondition(object columnValue) 
        {
            bool valueIsNull = null == columnValue || Convert.IsDBNull(columnValue);
            return valueIsNull == this.IsNull;
        } 
    }
 
    ///  
    /// Represents a simple value condition of the form (value IS NULL), (value IS NOT NULL)
    /// or (value EQ X). Supports IEquatable(Of ValueCondition) so that equivalent conditions 
    /// can be identified.
    /// 
    internal class ValueCondition : IEquatable
    { 
        internal readonly string Description;
        internal readonly bool IsSentinel; 
 
        internal const string IsNullDescription = "NULL";
        internal const string IsNotNullDescription = "NOT NULL"; 
        internal const string IsOtherDescription = "OTHER";

        internal readonly static ValueCondition IsNull = new ValueCondition(IsNullDescription, true);
        internal readonly static ValueCondition IsNotNull = new ValueCondition(IsNotNullDescription, true); 
        internal readonly static ValueCondition IsOther = new ValueCondition(IsOtherDescription, true);
 
        private ValueCondition(string description, bool isSentinel) 
        {
            Description = description; 
            IsSentinel = isSentinel;
        }

        internal ValueCondition(string description) 
            : this(description, false)
        { 
        } 

        internal bool IsNotNullCondition { get { return object.ReferenceEquals(this, IsNotNull); } } 

        public bool Equals(ValueCondition other)
        {
            return other.IsSentinel == this.IsSentinel && 
                other.Description == this.Description;
        } 
 
        public override int GetHashCode()
        { 
            return Description.GetHashCode();
        }

        public override string ToString() 
        {
            return this.Description; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Metadata.Edm;
using System.Collections.Generic; 
using System.Data.Common;
using System.Linq;
using System.Xml;
using System.Data.Common.Utils; 
using System.Data.Entity;
using OM = System.Collections.ObjectModel; 
using System.Globalization; 
using System.Diagnostics;
using System.Collections; 
using System.Data.Common.Utils.Boolean;
using System.Xml.XPath;
namespace System.Data.Mapping
{ 
    /// 
    /// Represents a mapping from a model FunctionImport to a store 
    /// non-composable Function. 
    /// 
    internal sealed class FunctionImportMapping 
    {
        internal FunctionImportMapping(EdmFunction targetFunction, EdmFunction functionImport,
            IEnumerable entityTypeMappings, ItemCollection itemCollection)
        { 
            this.TargetFunction = EntityUtil.CheckArgumentNull(targetFunction, "targetFunction");
            this.FunctionImport = EntityUtil.CheckArgumentNull(functionImport, "functionImport"); 
            EntityUtil.CheckArgumentNull(itemCollection, "itemCollection"); 

            // collect all mapped entity types 
            this.MappedEntityTypes = entityTypeMappings
                .SelectMany(mapping => mapping.GetMappedEntityTypes(itemCollection))
                .Distinct()
                .ToList() 
                .AsReadOnly();
 
            // collect all discriminator columns 
            this.DiscriminatorColumns = entityTypeMappings
                .SelectMany(mapping => mapping.GetDiscriminatorColumns()) 
                .Distinct()
                .ToList()
                .AsReadOnly();
 
            this.EntityTypeLineInfos = new KeyToListMap(EqualityComparer.Default);
            this.IsTypeOfLineInfos = new KeyToListMap(EqualityComparer.Default); 
 
            // normalize the type mappings
            var normalizedEntityTypeMappings = new List(); 
            foreach (var entityTypeMapping in entityTypeMappings)
            {
                // remember LineInfos for error reporting
                foreach (var entityType in entityTypeMapping.EntityTypes) 
                {
                    this.EntityTypeLineInfos.Add(entityType, entityTypeMapping.LineInfo); 
                } 
                foreach (var isTypeOf in entityTypeMapping.IsOfTypeEntityTypes)
                { 
                    this.IsTypeOfLineInfos.Add(isTypeOf, entityTypeMapping.LineInfo);
                }

                // create map from column name to condition 
                var columnMap = entityTypeMapping.Conditions.ToDictionary(
                    condition => condition.ColumnName, 
                    condition => condition); 

                // align conditions with discriminator columns 
                var columnMappings = new List(this.DiscriminatorColumns.Count);
                for (int i = 0; i < this.DiscriminatorColumns.Count; i++)
                {
                    string discriminatorColumn = this.DiscriminatorColumns[i]; 
                    FunctionImportEntityTypeMappingCondition mappingCondition;
                    if (columnMap.TryGetValue(discriminatorColumn, out mappingCondition)) 
                    { 
                        columnMappings.Add(mappingCondition);
                    } 
                    else
                    {
                        // null indicates the value for this discriminator doesn't matter
                        columnMappings.Add(null); 
                    }
                } 
 
                // create bit map for implied entity types
                bool[] impliedEntityTypesBitMap = new bool[this.MappedEntityTypes.Count]; 
                var impliedEntityTypesSet = new Set(entityTypeMapping.GetMappedEntityTypes(itemCollection));
                for (int i = 0; i < this.MappedEntityTypes.Count; i++)
                {
                    impliedEntityTypesBitMap[i] = impliedEntityTypesSet.Contains(this.MappedEntityTypes[i]); 
                }
 
                // construct normalized mapping 
                normalizedEntityTypeMappings.Add(new FunctionImportNormalizedEntityTypeMapping(this,
                    columnMappings, new BitArray(impliedEntityTypesBitMap))); 
            }

            this.NormalizedEntityTypeMappings = new OM.ReadOnlyCollection(
                normalizedEntityTypeMappings); 
        }
 
        ///  
        /// Gets store function (or target of the mapping)
        ///  
        internal readonly EdmFunction TargetFunction;

        /// 
        /// Gets model function (or source of the mapping) 
        /// 
        internal readonly EdmFunction FunctionImport; 
 
        /// 
        /// Gets all types in scope for this mapping. 
        /// 
        internal readonly OM.ReadOnlyCollection MappedEntityTypes;

        ///  
        /// Gets a list of all discriminator columns used in this mapping.
        ///  
        internal readonly OM.ReadOnlyCollection DiscriminatorColumns; 

        ///  
        /// Gets normalized representation of all EntityTypeMapping fragments for this
        /// function import mapping.
        /// 
        internal readonly OM.ReadOnlyCollection NormalizedEntityTypeMappings; 

        ///  
        /// Gets line infos for entity type mappings. 
        /// 
        internal readonly KeyToListMap EntityTypeLineInfos; 

        /// 
        /// Gets line infos for IsTypeOf mappings for entity types.
        ///  
        internal readonly KeyToListMap IsTypeOfLineInfos;
 
        ///  
        /// Given discriminator values (ordinally aligned with DiscriminatorColumns), determines
        /// the entity type to return. Throws a CommandExecutionException if the type is ambiguous. 
        /// 
        internal EntityType Discriminate(object[] discriminatorValues)
        {
            // initialize matching types bit map 
            BitArray typeCandidates = new BitArray(this.MappedEntityTypes.Count, true);
 
            foreach (var typeMapping in this.NormalizedEntityTypeMappings) 
            {
                // check if this type mapping is matched 
                bool matches = true;
                var columnConditions = typeMapping.ColumnConditions;
                for (int i = 0; i < columnConditions.Count; i++)
                { 
                    if (null != columnConditions[i] && // this discriminator doesn't matter for the given condition
                        !columnConditions[i].ColumnValueMatchesCondition(discriminatorValues[i])) 
                    { 
                        matches = false;
                        break; 
                    }
                }

                if (matches) 
                {
                    // if the type condition is met, narrow the set of type candidates 
                    typeCandidates = typeCandidates.And(typeMapping.ImpliedEntityTypes); 
                }
                else 
                {
                    // if the type condition fails, all implied types are eliminated
                    // (the type mapping fragment is a co-implication, so a type is no longer
                    // a candidate if any condition referring to it is false) 
                    typeCandidates = typeCandidates.And(typeMapping.ComplementImpliedEntityTypes);
                } 
            } 

            // find matching type condition 
            EntityType entityType = null;
            for (int i = 0; i < typeCandidates.Length; i++)
            {
                if (typeCandidates[i]) 
                {
                    if (null != entityType) 
                    { 
                        throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
                    } 
                    entityType = this.MappedEntityTypes[i];
                }
            }
 
            // if there is no match, raise an exception
            if (null == entityType) 
            { 
                throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
            } 

            return entityType;
        }
 
        /// 
        /// Determines which explicitly mapped types in the function import mapping cannot be generated. 
        /// For IsTypeOf declarations, reports if no type in hierarchy can be produced. 
        ///
        /// Works by: 
        ///
        /// - Converting type mapping conditions into vertices
        /// - Checking that some assignment satisfies
        ///  
        internal void GetUnreachableTypes(EdmItemCollection itemCollection,
            out KeyToListMap unreachableEntityTypes, 
            out KeyToListMap unreachableIsTypeOfs) 
        {
            // Contains, for each DiscriminatorColumn, a domain variable where the domain values are 
            // integers representing the ordinal within discriminatorDomains
            DomainVariable[] variables = ConstructDomainVariables();

            // Convert type mapping conditions to decision diagram vertices 
            var converter = new DomainConstraintConversionContext();
            Vertex[] mappingConditions = ConvertMappingConditionsToVertices(converter, variables); 
 
            // Find reachable types
            Set reachableTypes = FindReachableTypes(converter, mappingConditions); 

            CollectUnreachableTypes(itemCollection, reachableTypes, out unreachableEntityTypes, out unreachableIsTypeOfs);
        }
 
        /// 
        /// Determines the expected shape of store results. We expect a column for every property 
        /// of the mapped type (or types) and a column for every discriminator column. We make no 
        /// assumptions about the order of columns: the provider is expected to determine appropriate
        /// types by looking at the names of the result columns, not the order of columns, which is 
        /// different from the typical handling of row types in the EF.
        /// 
        /// 
        /// Requires that the given function import mapping refers to a Collection(Entity) CSDL 
        /// function.
        ///  
        /// Row type. 
        internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace)
        { 
            // Collect all columns as name-type pairs.
            Dictionary columns = new Dictionary();

            // Figure out which entity types we expect to yield from the function. 
            IEnumerable entityTypes;
            if (0 == this.NormalizedEntityTypeMappings.Count) 
            { 
                // No explicit type mappings; just use the base entity type.
                EntityType entityType; 
                MetadataHelper.TryGetFunctionImportReturnEntityType(this.FunctionImport, out entityType);
                Debug.Assert(null != entityType, "this method must be called only for entity reader function imports");
                entityTypes = new EntityType[] { entityType };
            } 
            else
            { 
                // Types are explicitly mapped. 
                entityTypes = this.MappedEntityTypes;
            } 

            // Gather columns corresponding to all entity properties.
            foreach (EntityType entityType in entityTypes)
            { 
                foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(entityType))
                { 
                    // NOTE: if a complex type is encountered, the column map generator will 
                    // throw. For now, we just let them through.
 
                    // We expect to see each property multiple times, so we use .item rather than
                    // .Add.
                    columns[property.Name] = property.TypeUsage;
                } 
            }
 
            // Gather discriminator columns. 
            foreach (string discriminatorColumn in this.DiscriminatorColumns)
            { 
                if (!columns.ContainsKey(discriminatorColumn))
                {
                    //
 

 
 

 
                    TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false);
                    columns.Add(discriminatorColumn, type);
                }
            } 

            // Expected type is a collection of rows 
            RowType rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value))); 
            TypeUsage result = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType)));
            return result; 
        }

        /// 
        /// Determines which types are produced by this mapping 
        /// 
        private Set FindReachableTypes(DomainConstraintConversionContext converter, 
            Vertex[] mappingConditions) 
        {
            Set reachableTypes = new Set(); 

            // for each entity type, create a candidate function that evaluates to true given
            // discriminator assignments iff. all of that type's conditions evaluate to true
            // and its negative conditions evaluate to false 
            Vertex[] candidateFunctions = new Vertex[this.MappedEntityTypes.Count];
            for (int i = 0; i < candidateFunctions.Length; i++) 
            { 
                // seed the candidate function conjunction with 'true'
                Vertex candidateFunction = Vertex.One; 
                for (int j = 0; j < this.NormalizedEntityTypeMappings.Count; j++)
                {
                    var entityTypeMapping = this.NormalizedEntityTypeMappings[j];
 
                    // determine if this mapping is a positive or negative case for the current type
                    if (entityTypeMapping.ImpliedEntityTypes[i]) 
                    { 
                        candidateFunction = converter.Solver.And(candidateFunction, mappingConditions[j]);
                    } 
                    else
                    {
                        candidateFunction = converter.Solver.And(candidateFunction, converter.Solver.Not(mappingConditions[j]));
                    } 
                }
                candidateFunctions[i] = candidateFunction; 
            } 

            // for each type, make sure there is some assignment that resolves to only that type 
            for (int i = 0; i < candidateFunctions.Length; i++)
            {
                // create a function that evaluates to true iff. the current candidate function is true
                // and every other candidate function is false 
                Vertex isExactlyThisTypeCondition = converter.Solver.And(
                    candidateFunctions.Select((typeCondition, ordinal) => ordinal == i ? 
                        typeCondition : 
                        converter.Solver.Not(typeCondition)));
 
                // if the above conjunction is satisfiable, it means some row configuration exists
                // producing the type
                if (!isExactlyThisTypeCondition.IsZero())
                { 
                    reachableTypes.Add(this.MappedEntityTypes[i]);
                } 
            } 
            return reachableTypes;
        } 

        private void CollectUnreachableTypes(EdmItemCollection itemCollection, Set reachableTypes, out KeyToListMap entityTypes, out KeyToListMap isTypeOfEntityTypes)
        {
            // Collect line infos for types in violation 
            entityTypes = new KeyToListMap(EqualityComparer.Default);
            isTypeOfEntityTypes = new KeyToListMap(EqualityComparer.Default); 
 
            if (reachableTypes.Count == this.MappedEntityTypes.Count)
            { 
                // All types are reachable; nothing to check
                return;
            }
 
            // Find IsTypeOf mappings where no type in hierarchy can generate a row
            foreach (var isTypeOf in this.IsTypeOfLineInfos.Keys) 
            { 
                if (!MetadataHelper.GetTypeAndSubtypesOf(isTypeOf, itemCollection, false)
                    .Cast() 
                    .Intersect(reachableTypes)
                    .Any())
                {
                    // no type in the hierarchy is reachable... 
                    isTypeOfEntityTypes.AddRange(isTypeOf, this.IsTypeOfLineInfos.EnumerateValues(isTypeOf));
                } 
            } 

            // Find explicit types not generating a value 
            foreach (var entityType in this.EntityTypeLineInfos.Keys)
            {
                if (!reachableTypes.Contains(entityType))
                { 
                    entityTypes.AddRange(entityType, this.EntityTypeLineInfos.EnumerateValues(entityType));
                } 
            } 
        }
 
        private DomainVariable[] ConstructDomainVariables()
        {
            // determine domain for each discriminator column, including "other" and "null" placeholders
            var discriminatorDomains = new Set[this.DiscriminatorColumns.Count]; 
            for (int i = 0; i < discriminatorDomains.Length; i++)
            { 
                discriminatorDomains[i] = new Set(); 
                discriminatorDomains[i].Add(ValueCondition.IsOther);
                discriminatorDomains[i].Add(ValueCondition.IsNull); 
            }

            // collect all domain values
            foreach (var typeMapping in this.NormalizedEntityTypeMappings) 
            {
                for (int i = 0; i < this.DiscriminatorColumns.Count; i++) 
                { 
                    var discriminatorValue = typeMapping.ColumnConditions[i];
                    if (null != discriminatorValue && 
                        !discriminatorValue.ConditionValue.IsNotNullCondition) // NotNull is a special range (everything but IsNull)
                    {
                        discriminatorDomains[i].Add(discriminatorValue.ConditionValue);
                    } 
                }
            } 
 
            var discriminatorVariables = new DomainVariable[discriminatorDomains.Length];
            for (int i = 0; i < discriminatorVariables.Length; i++) 
            {
                // domain variable is identified by the column name and takes all collected domain values
                discriminatorVariables[i] = new DomainVariable(this.DiscriminatorColumns[i],
                    discriminatorDomains[i].MakeReadOnly()); 
            }
 
            return discriminatorVariables; 
        }
 
        private Vertex[] ConvertMappingConditionsToVertices(ConversionContext> converter,
            DomainVariable[] variables)
        {
            Vertex[] conditions = new Vertex[this.NormalizedEntityTypeMappings.Count]; 
            for (int i = 0; i < conditions.Length; i++)
            { 
                var typeMapping = this.NormalizedEntityTypeMappings[i]; 

                // create conjunction representing the condition 
                Vertex condition = Vertex.One;
                for (int j = 0; j < this.DiscriminatorColumns.Count; j++)
                {
                    var columnCondition = typeMapping.ColumnConditions[j]; 
                    if (null != columnCondition)
                    { 
                        var conditionValue = columnCondition.ConditionValue; 
                        if (conditionValue.IsNotNullCondition)
                        { 
                            // the 'not null' condition is not actually part of the domain (since it
                            // covers other elements), so create a Not(value in {null}) condition
                            var isNull = new TermExpr>(
                                new DomainConstraint(variables[j], ValueCondition.IsNull)); 
                            Vertex isNullVertex = converter.TranslateTermToVertex(isNull);
                            condition = converter.Solver.And(condition, converter.Solver.Not(isNullVertex)); 
                        } 
                        else
                        { 
                            var hasValue = new TermExpr>(
                                new DomainConstraint(variables[j], conditionValue));
                            condition = converter.Solver.And(condition, converter.TranslateTermToVertex(hasValue));
                        } 
                    }
                } 
                conditions[i] = condition; 
            }
            return conditions; 
        }
    }

    internal sealed class FunctionImportNormalizedEntityTypeMapping 
    {
        internal FunctionImportNormalizedEntityTypeMapping(FunctionImportMapping parent, 
            List columnConditions, BitArray impliedEntityTypes) 
        {
            // validate arguments 
            EntityUtil.CheckArgumentNull(parent, "parent");
            EntityUtil.CheckArgumentNull(columnConditions, "discriminatorValues");
            EntityUtil.CheckArgumentNull(impliedEntityTypes, "impliedEntityTypes");
 
            Debug.Assert(columnConditions.Count == parent.DiscriminatorColumns.Count,
                "discriminator values must be ordinally aligned with discriminator columns"); 
            Debug.Assert(impliedEntityTypes.Count == parent.MappedEntityTypes.Count, 
                "implied entity types must be ordinally aligned with mapped entity types");
 
            this.ColumnConditions = new OM.ReadOnlyCollection(columnConditions.ToList());
            this.ImpliedEntityTypes = impliedEntityTypes;
            this.ComplementImpliedEntityTypes = (new BitArray(this.ImpliedEntityTypes)).Not();
        } 

        ///  
        /// Gets discriminator values aligned with DiscriminatorColumns of the parent FunctionImportMapping. 
        /// A null ValueCondition indicates 'anything goes'.
        ///  
        internal readonly OM.ReadOnlyCollection ColumnConditions;

        /// 
        /// Gets bit array with 'true' indicating the corresponding MappedEntityType of the parent 
        /// FunctionImportMapping is implied by this fragment.
        ///  
        internal readonly BitArray ImpliedEntityTypes; 

        ///  
        /// Gets the complement of the ImpliedEntityTypes BitArray.
        /// 
        internal readonly BitArray ComplementImpliedEntityTypes;
 
        public override string ToString()
        { 
            return String.Format(CultureInfo.InvariantCulture, "Values={0}, Types={1}", 
                StringUtil.ToCommaSeparatedString(this.ColumnConditions), StringUtil.ToCommaSeparatedString(this.ImpliedEntityTypes));
        } 
    }

    internal sealed class FunctionImportEntityTypeMapping
    { 
        internal FunctionImportEntityTypeMapping(IEnumerable isOfTypeEntityTypes,
            IEnumerable entityTypes, IEnumerable conditions, 
            IXmlLineInfo lineInfo) 
        {
            this.IsOfTypeEntityTypes = new OM.ReadOnlyCollection( 
                EntityUtil.CheckArgumentNull(isOfTypeEntityTypes, "isOfTypeEntityTypes").ToList());
            this.EntityTypes = new OM.ReadOnlyCollection(
                EntityUtil.CheckArgumentNull(entityTypes, "entityTypes").ToList());
            this.Conditions = new OM.ReadOnlyCollection( 
                EntityUtil.CheckArgumentNull(conditions, "conditions").ToList());
            this.LineInfo = lineInfo; 
        } 

        internal readonly OM.ReadOnlyCollection Conditions; 
        internal readonly OM.ReadOnlyCollection EntityTypes;
        internal readonly OM.ReadOnlyCollection IsOfTypeEntityTypes;
        internal readonly IXmlLineInfo LineInfo;
 
        /// 
        /// Gets all (concrete) entity types implied by this type mapping. 
        ///  
        internal IEnumerable GetMappedEntityTypes(ItemCollection itemCollection)
        { 
            const bool includeAbstractTypes = false;
            return this.EntityTypes.Concat(
                this.IsOfTypeEntityTypes.SelectMany(entityType =>
                    MetadataHelper.GetTypeAndSubtypesOf(entityType, itemCollection, includeAbstractTypes) 
                    .Cast()));
        } 
 
        internal IEnumerable GetDiscriminatorColumns()
        { 
            return this.Conditions.Select(condition => condition.ColumnName);
        }
    }
 
    internal abstract class FunctionImportEntityTypeMappingCondition
    { 
        protected FunctionImportEntityTypeMappingCondition(string columnName) 
        {
            this.ColumnName = EntityUtil.CheckArgumentNull(columnName, "columnName"); 
        }

        internal abstract ValueCondition ConditionValue { get; }
 
        internal readonly string ColumnName;
 
        internal abstract bool ColumnValueMatchesCondition(object columnValue); 

        public override string ToString() 
        {
            return this.ConditionValue.ToString();
        }
    } 

    internal sealed class FunctionImportEntityTypeMappingConditionValue : FunctionImportEntityTypeMappingCondition 
    { 
        internal FunctionImportEntityTypeMappingConditionValue(string columnName, XPathNavigator columnValue)
            : base(columnName) 
        {
            this._xPathValue = EntityUtil.CheckArgumentNull(columnValue, "columnValue");
            this._convertedValues = new Memoizer(this.GetConditionValue, null);
        } 

        private readonly XPathNavigator _xPathValue; 
        private readonly Memoizer _convertedValues; 

        internal override ValueCondition ConditionValue 
        {
            get { return new ValueCondition(_xPathValue.Value); }
        }
 
        internal override bool ColumnValueMatchesCondition(object columnValue)
        { 
            if (null == columnValue || Convert.IsDBNull(columnValue)) 
            {
                // only FunctionImportEntityTypeMappingConditionIsNull can match a null 
                // column value
                return false;
            }
 
            Type columnValueType = columnValue.GetType();
 
            // check if we've interpreted this column type yet 
            object conditionValue = _convertedValues.Evaluate(columnValueType);
            return CdpEqualityComparer.DefaultEqualityComparer.Equals(columnValue, conditionValue); 
        }

        private object GetConditionValue(Type columnValueType)
        { 
            object conditionValue;
 
            // check that the type is supported 
            PrimitiveType primitiveType;
            if (!ClrProviderManifest.Instance.TryGetPrimitiveType(columnValueType, out primitiveType) || 
                !StorageMappingItemLoader.IsTypeSupportedForCondition(primitiveType.PrimitiveTypeKind))
            {
                throw EntityUtil.CommandExecution(Strings.Mapping_FunctionImport_UnsupportedType(
                    this.ColumnName, columnValueType.FullName)); 
            }
 
            try 
            {
                conditionValue = _xPathValue.ValueAs(columnValueType); 
            }
            catch (FormatException)
            {
                throw EntityUtil.CommandExecution(Strings.Mapping_FunctionImport_ConditionValueTypeMismatch( 
                    StorageMslConstructs.FunctionImportMappingElement, this.ColumnName, columnValueType.FullName));
            } 
 
            return conditionValue;
        } 
    }

    internal sealed class FunctionImportEntityTypeMappingConditionIsNull : FunctionImportEntityTypeMappingCondition
    { 
        internal FunctionImportEntityTypeMappingConditionIsNull(string columnName, bool isNull)
            : base(columnName) 
        { 
            this.IsNull = isNull;
        } 

        internal readonly bool IsNull;

        internal override ValueCondition ConditionValue 
        {
            get { return IsNull ? ValueCondition.IsNull : ValueCondition.IsNotNull; } 
        } 

        internal override bool ColumnValueMatchesCondition(object columnValue) 
        {
            bool valueIsNull = null == columnValue || Convert.IsDBNull(columnValue);
            return valueIsNull == this.IsNull;
        } 
    }
 
    ///  
    /// Represents a simple value condition of the form (value IS NULL), (value IS NOT NULL)
    /// or (value EQ X). Supports IEquatable(Of ValueCondition) so that equivalent conditions 
    /// can be identified.
    /// 
    internal class ValueCondition : IEquatable
    { 
        internal readonly string Description;
        internal readonly bool IsSentinel; 
 
        internal const string IsNullDescription = "NULL";
        internal const string IsNotNullDescription = "NOT NULL"; 
        internal const string IsOtherDescription = "OTHER";

        internal readonly static ValueCondition IsNull = new ValueCondition(IsNullDescription, true);
        internal readonly static ValueCondition IsNotNull = new ValueCondition(IsNotNullDescription, true); 
        internal readonly static ValueCondition IsOther = new ValueCondition(IsOtherDescription, true);
 
        private ValueCondition(string description, bool isSentinel) 
        {
            Description = description; 
            IsSentinel = isSentinel;
        }

        internal ValueCondition(string description) 
            : this(description, false)
        { 
        } 

        internal bool IsNotNullCondition { get { return object.ReferenceEquals(this, IsNotNull); } } 

        public bool Equals(ValueCondition other)
        {
            return other.IsSentinel == this.IsSentinel && 
                other.Description == this.Description;
        } 
 
        public override int GetHashCode()
        { 
            return Description.GetHashCode();
        }

        public override string ToString() 
        {
            return this.Description; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK