FunctionImportMapping.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Mapping / FunctionImportMapping.cs / 1305376 / FunctionImportMapping.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Metadata.Edm; 
using System.Collections.Generic;
using System.Data.Common;
using System.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;
using System.Collections.ObjectModel; 
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 structuralTypeMappings, ItemCollection itemCollection)
        { 
            this.TargetFunction = EntityUtil.CheckArgumentNull(targetFunction, "targetFunction"); 
            this.FunctionImport = EntityUtil.CheckArgumentNull(functionImport, "functionImport");
            EntityUtil.CheckArgumentNull(itemCollection, "itemCollection"); 
            EntityUtil.CheckArgumentNull(structuralTypeMappings, "structuralTypeMappings");

            Dictionary> isOfTypeEntityTypeColumnsRenameMapping =
                new Dictionary>(); 
            Dictionary> entityTypeColumnsRenameMapping =
                new Dictionary>(); 
            // normalize the type mappings 
            var normalizedEntityTypeMappings = new List();
 
            // if no specific type mapping
            if(structuralTypeMappings.Count() == 0)
            {
                // initialize 
                this.ReturnTypeColumnsRenameMapping = new Dictionary();
                this.NormalizedEntityTypeMappings = 
                    new System.Collections.ObjectModel.ReadOnlyCollection( 
                        normalizedEntityTypeMappings);
                this.DiscriminatorColumns = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { }); 
                this.MappedEntityTypes = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { });
                return;
            }
 
            IEnumerable entityTypeMappings =
                structuralTypeMappings.OfType(); 
 
            // FunctionImportEntityTypeMapping
            if (null != entityTypeMappings && null != entityTypeMappings.FirstOrDefault()) 
            {
                // 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);
 
                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))); 

                    // construct the rename mappings by adding isTypeOf types and specific entity types to the corresponding lists
                    foreach (var isOfType in entityTypeMapping.IsOfTypeEntityTypes)
                    { 
                        if (!isOfTypeEntityTypeColumnsRenameMapping.Keys.Contains(isOfType))
                        { 
                            isOfTypeEntityTypeColumnsRenameMapping.Add(isOfType, entityTypeMapping.ColumnsRenameList); 
                        }
                        else 
                        {
                            foreach (var rename in entityTypeMapping.ColumnsRenameList)
                            {
                                isOfTypeEntityTypeColumnsRenameMapping[isOfType].Add(rename); 
                            }
                        } 
                    } 
                    foreach (var entityType in entityTypeMapping.EntityTypes)
                    { 
                        if (!entityTypeColumnsRenameMapping.Keys.Contains(entityType))
                        {
                            entityTypeColumnsRenameMapping.Add(entityType, entityTypeMapping.ColumnsRenameList);
                        } 
                        else
                        { 
                            foreach (var rename in entityTypeMapping.ColumnsRenameList) 
                            {
                                entityTypeColumnsRenameMapping[entityType].Add(rename); 
                            }
                        }
                    }
                } 
                this.ReturnTypeColumnsRenameMapping =
                    new FunctionImportReturnTypeEntityTypeColumnsRenameBuilder( 
                        isOfTypeEntityTypeColumnsRenameMapping, entityTypeColumnsRenameMapping).ColumnRenameMapping; 

                this.NormalizedEntityTypeMappings = new OM.ReadOnlyCollection( 
                    normalizedEntityTypeMappings);
            }
            else
            { 
                // FunctionImportComplexTypeMapping
                Debug.Assert(structuralTypeMappings.First() is FunctionImportComplexTypeMapping, "only two types can have renames, complexType and entityType"); 
                IEnumerable complexTypeMappings = structuralTypeMappings.Cast(); 

                Debug.Assert(complexTypeMappings.Count() == 1, "how come there are more than 1, complex type cannot derive from other complex type"); 

                this.ReturnTypeColumnsRenameMapping = new Dictionary();
                foreach (var rename in complexTypeMappings.First().ColumnsRenameList)
                { 
                    FunctionImportReturnTypeStructuralTypeColumnRenameMapping columnRenameMapping = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(rename.CMember);
                    columnRenameMapping.AddRename(new FunctionImportReturnTypeStructuralTypeColumn( 
                            rename.SColumn, 
                            complexTypeMappings.First().ReturnType,
                            false)); 
                    this.ReturnTypeColumnsRenameMapping.Add(rename.CMember, columnRenameMapping);
                }

                // initialize the extra data 
                this.NormalizedEntityTypeMappings =
                    new System.Collections.ObjectModel.ReadOnlyCollection( 
                        normalizedEntityTypeMappings); 
                this.DiscriminatorColumns = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { });
                this.MappedEntityTypes = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { }); 
            }

        }
 
        /// 
        /// 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;
 
        /// 
        /// Get the columns rename mapping for return type, the first string is the member name 
        /// the second one is column names for different types that mentioned in the mapping. 
        /// 
        internal readonly Dictionary ReturnTypeColumnsRenameMapping; 

        /// 
        /// 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) or Collection(ComplexType) 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 structuralTypes; 
            if (0 == this.NormalizedEntityTypeMappings.Count)
            {
                // No explicit type mappings; just use the type specified in the ReturnType attribute on the function.
                StructuralType structuralType; 
                MetadataHelper.TryGetFunctionImportReturnType(this.FunctionImport, out structuralType);
                Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); 
                structuralTypes = new StructuralType[] { structuralType }; 
            }
            else 
            {
                // Types are explicitly mapped.
                structuralTypes = this.MappedEntityTypes.Cast();
            } 

            // Gather columns corresponding to all properties. 
            foreach (StructuralType structuralType in structuralTypes) 
            {
                foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) 
                {
                    // 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 indexer 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 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 ByValueEqualityComparer.Default.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       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

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;
using System.Collections.ObjectModel; 
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 structuralTypeMappings, ItemCollection itemCollection)
        { 
            this.TargetFunction = EntityUtil.CheckArgumentNull(targetFunction, "targetFunction"); 
            this.FunctionImport = EntityUtil.CheckArgumentNull(functionImport, "functionImport");
            EntityUtil.CheckArgumentNull(itemCollection, "itemCollection"); 
            EntityUtil.CheckArgumentNull(structuralTypeMappings, "structuralTypeMappings");

            Dictionary> isOfTypeEntityTypeColumnsRenameMapping =
                new Dictionary>(); 
            Dictionary> entityTypeColumnsRenameMapping =
                new Dictionary>(); 
            // normalize the type mappings 
            var normalizedEntityTypeMappings = new List();
 
            // if no specific type mapping
            if(structuralTypeMappings.Count() == 0)
            {
                // initialize 
                this.ReturnTypeColumnsRenameMapping = new Dictionary();
                this.NormalizedEntityTypeMappings = 
                    new System.Collections.ObjectModel.ReadOnlyCollection( 
                        normalizedEntityTypeMappings);
                this.DiscriminatorColumns = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { }); 
                this.MappedEntityTypes = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { });
                return;
            }
 
            IEnumerable entityTypeMappings =
                structuralTypeMappings.OfType(); 
 
            // FunctionImportEntityTypeMapping
            if (null != entityTypeMappings && null != entityTypeMappings.FirstOrDefault()) 
            {
                // 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);
 
                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))); 

                    // construct the rename mappings by adding isTypeOf types and specific entity types to the corresponding lists
                    foreach (var isOfType in entityTypeMapping.IsOfTypeEntityTypes)
                    { 
                        if (!isOfTypeEntityTypeColumnsRenameMapping.Keys.Contains(isOfType))
                        { 
                            isOfTypeEntityTypeColumnsRenameMapping.Add(isOfType, entityTypeMapping.ColumnsRenameList); 
                        }
                        else 
                        {
                            foreach (var rename in entityTypeMapping.ColumnsRenameList)
                            {
                                isOfTypeEntityTypeColumnsRenameMapping[isOfType].Add(rename); 
                            }
                        } 
                    } 
                    foreach (var entityType in entityTypeMapping.EntityTypes)
                    { 
                        if (!entityTypeColumnsRenameMapping.Keys.Contains(entityType))
                        {
                            entityTypeColumnsRenameMapping.Add(entityType, entityTypeMapping.ColumnsRenameList);
                        } 
                        else
                        { 
                            foreach (var rename in entityTypeMapping.ColumnsRenameList) 
                            {
                                entityTypeColumnsRenameMapping[entityType].Add(rename); 
                            }
                        }
                    }
                } 
                this.ReturnTypeColumnsRenameMapping =
                    new FunctionImportReturnTypeEntityTypeColumnsRenameBuilder( 
                        isOfTypeEntityTypeColumnsRenameMapping, entityTypeColumnsRenameMapping).ColumnRenameMapping; 

                this.NormalizedEntityTypeMappings = new OM.ReadOnlyCollection( 
                    normalizedEntityTypeMappings);
            }
            else
            { 
                // FunctionImportComplexTypeMapping
                Debug.Assert(structuralTypeMappings.First() is FunctionImportComplexTypeMapping, "only two types can have renames, complexType and entityType"); 
                IEnumerable complexTypeMappings = structuralTypeMappings.Cast(); 

                Debug.Assert(complexTypeMappings.Count() == 1, "how come there are more than 1, complex type cannot derive from other complex type"); 

                this.ReturnTypeColumnsRenameMapping = new Dictionary();
                foreach (var rename in complexTypeMappings.First().ColumnsRenameList)
                { 
                    FunctionImportReturnTypeStructuralTypeColumnRenameMapping columnRenameMapping = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(rename.CMember);
                    columnRenameMapping.AddRename(new FunctionImportReturnTypeStructuralTypeColumn( 
                            rename.SColumn, 
                            complexTypeMappings.First().ReturnType,
                            false)); 
                    this.ReturnTypeColumnsRenameMapping.Add(rename.CMember, columnRenameMapping);
                }

                // initialize the extra data 
                this.NormalizedEntityTypeMappings =
                    new System.Collections.ObjectModel.ReadOnlyCollection( 
                        normalizedEntityTypeMappings); 
                this.DiscriminatorColumns = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { });
                this.MappedEntityTypes = new System.Collections.ObjectModel.ReadOnlyCollection(new List() { }); 
            }

        }
 
        /// 
        /// 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;
 
        /// 
        /// Get the columns rename mapping for return type, the first string is the member name 
        /// the second one is column names for different types that mentioned in the mapping. 
        /// 
        internal readonly Dictionary ReturnTypeColumnsRenameMapping; 

        /// 
        /// 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) or Collection(ComplexType) 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 structuralTypes; 
            if (0 == this.NormalizedEntityTypeMappings.Count)
            {
                // No explicit type mappings; just use the type specified in the ReturnType attribute on the function.
                StructuralType structuralType; 
                MetadataHelper.TryGetFunctionImportReturnType(this.FunctionImport, out structuralType);
                Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports"); 
                structuralTypes = new StructuralType[] { structuralType }; 
            }
            else 
            {
                // Types are explicitly mapped.
                structuralTypes = this.MappedEntityTypes.Cast();
            } 

            // Gather columns corresponding to all properties. 
            foreach (StructuralType structuralType in structuralTypes) 
            {
                foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType)) 
                {
                    // 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 indexer 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 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 ByValueEqualityComparer.Default.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