CellCreator.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 / Map / ViewGeneration / CellCreator.cs / 1305376 / CellCreator.cs

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

using System.Data.Common.Utils; 
using System.Data.Mapping.ViewGeneration.Structures;
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.Utils;
using System.Diagnostics; 
using System.Data.Metadata.Edm;
using System.Linq; 
 
namespace System.Data.Mapping.ViewGeneration
{ 


    // A class that handles creation of cells from the meta data information
    internal class CellCreator : InternalBase 
    {
 
        #region Constructors 
        // effects: Creates a cell creator object for an entity container's
        // mappings (specified in "maps") 
        internal CellCreator(StorageEntityContainerMapping containerMapping)
        {
            m_containerMapping = containerMapping;
            m_identifiers = new CqlIdentifiers(); 
        }
        #endregion 
 
        #region Fields
        // The mappings from the metadata for different containers 
        private StorageEntityContainerMapping m_containerMapping;
        private int m_currentCellNumber;
        private CqlIdentifiers m_identifiers;
        // Keep track of all the identifiers to prevent clashes with _from0, 
        // _from1, T, T1, etc
        // Keep track of names of 
        // * Entity Containers 
        // * Extent names
        // * Entity Types 
        // * Complex Types
        // * Properties
        // * Roles
        #endregion 

        #region Properties 
        // effects: Returns the set of identifiers used in this 
        internal CqlIdentifiers Identifiers
        { 
            get { return m_identifiers; }
        }
        #endregion
 
        #region External methods
        // effects: Generates the cells for all the entity containers 
        // specified in this. The generated cells are geared for query view generation 
        internal List GenerateCells(ConfigViewGenerator config)
        { 
            List cells = new List();

            if (config.IsNormalTracing)
            { 
                m_containerMapping.Print(0);
            } 
            // Get the cells from the entity container metadata 
            ExtractCells(cells);
 
            ExpandCells(cells);

            // Get the identifiers from the cells
            m_identifiers.AddIdentifier(m_containerMapping.EdmEntityContainer.Name); 
            m_identifiers.AddIdentifier(m_containerMapping.StorageEntityContainer.Name);
            foreach (Cell cell in cells) 
            { 
                cell.GetIdentifiers(m_identifiers);
            } 

            return cells;
        }
        #endregion 

        #region Private Methods 
        ///  
        /// Boolean members have a closed domain and are enumerated when domains are established i.e. (T, F) instead of (notNull).
        /// Query Rewriting is exercised over every domain of the condition member. If the member contains not_null condition 
        /// for example, it cannot generate a view for partitions (member=T), (Member=F). For this reason we need to expand the cells
        /// in a predefined situation (below) to include sub-fragments mapping individual elements of the closed domain.
        /// Enums (a planned feature) need to be handled in a similar fashion.
        /// 
        /// Find booleans that are projected with a not_null condition
        /// Expand ALL cells where they are projected. Why? See Unit Test case NullabilityConditionOnBoolean5.es 
        /// Validation will fail because it will not be able to validate rewritings for partitions on the 'other' cells. 
        /// 
        private void ExpandCells(List cells) 
        {
            var sSideMembersToBeExpanded = new Set();

            foreach (Cell cell in cells) 
            {
                //Find Projected members that are Boolean AND are mentioned in the Where clause with not_null condition 
                foreach (var memberToExpand in cell.SQuery.GetProjectedMembers() 
                                            .Where(member => IsBooleanMember(member))
                                            .Where(boolMember => cell.SQuery.GetConjunctsFromWhereClause() 
                                                                    .Where(restriction => restriction.Domain.Values.Contains(Constant.NotNull))
                                                                    .Select(restriction => restriction.RestrictedMemberSlot.MemberPath).Contains(boolMember)))
                {
                    sSideMembersToBeExpanded.Add(memberToExpand); 
                }
            } 
 
            //Foreach s-side members, find all c-side members it is mapped to
            //  We need these because we need to expand all cells where the  boolean candidate is projected or mapped member is projected, e.g: 
            //   (1) C[id, cdisc] WHERE d=true   <=>   T1[id, sdisc] WHERE sdisc=NOTNULL
            //   (2) C[id, cdisc] WHERE d=false  <=>   T2[id, sdisc]
            //  Here we need to know that because of T1.sdisc, we need to expand T2.sdisc.
            //  This is done by tracking cdisc, and then seeing in cell 2 that it is mapped to T2.sdisc 

            var cSideMembersForSSideExpansionCandidates = new Dictionary>(); 
            foreach (Cell cell in cells) 
            {
                foreach (var sSideMemberToExpand in sSideMembersToBeExpanded) 
                {
                    var cSideMembers = cell.SQuery.GetProjectedPositions(sSideMemberToExpand).Select(pos => ((MemberProjectedSlot)cell.CQuery.ProjectedSlotAt(pos)).MemberPath);

                    Set cSidePaths = null; 
                    if (!cSideMembersForSSideExpansionCandidates.TryGetValue(sSideMemberToExpand, out cSidePaths))
                    { 
                        cSidePaths = new Set(); 
                        cSideMembersForSSideExpansionCandidates[sSideMemberToExpand] = cSidePaths;
                    } 

                    cSidePaths.AddRange(cSideMembers);
                }
            } 

            // Expand cells that project members collected earlier with T/F conditiions 
            foreach (Cell cell in cells.ToArray()) 
            {
                //Each member gets its own expansion. Including multiple condition candidates in one SQuery 
                // "... <=> T[..] WHERE a=notnull AND b=notnull" means a and b get their own independent expansions
                // Note: this is not a cross-product
                foreach (var memberToExpand in sSideMembersToBeExpanded)
                { 
                    var mappedCSideMembers = cSideMembersForSSideExpansionCandidates[memberToExpand];
 
                    //Check if member is projected in this cell. 
                    if (cell.SQuery.GetProjectedMembers().Contains(memberToExpand))
                    { 
                        // Creationg additional cel can fail when the condition to be appended contradicts existing condition in the CellQuery
                        // We don't add contradictions because they seem to cause unrelated problems in subsequent validation routines
                        Cell resultCell = null;
                        if (TryCreateAdditionalCellWithCondition(cell, memberToExpand, true  /*condition value*/, ViewTarget.UpdateView /*s-side member*/, out resultCell)) 
                        {
                            cells.Add(resultCell); 
                        } 
                        if (TryCreateAdditionalCellWithCondition(cell, memberToExpand, false /*condition value*/, ViewTarget.UpdateView /*s-side member*/, out resultCell))
                        { 
                            cells.Add(resultCell);
                        }
                    }
                    else 
                    {  //If the s-side member is not projected, see if the mapped C-side member(s) is projected
                        foreach (var cMemberToExpand in cell.CQuery.GetProjectedMembers().Intersect(mappedCSideMembers)) 
                        { 
                            Cell resultCell = null;
                            if (TryCreateAdditionalCellWithCondition(cell, cMemberToExpand, true  /*condition value*/, ViewTarget.QueryView /*c-side member*/, out resultCell)) 
                            {
                                cells.Add(resultCell);
                            }
 
                            if (TryCreateAdditionalCellWithCondition(cell, cMemberToExpand, false /*condition value*/, ViewTarget.QueryView /*c-side member*/, out resultCell))
                            { 
                                cells.Add(resultCell); 
                            }
                        } 
                    }
                }
            }
 
        }
 
 

        ///  
        /// Given a cell, a member and a boolean condition on that member, creates additional cell
        /// which with the specified restriction on the member in addition to original condition.
        /// e.i conjunction of original condition AND member in newCondition
        /// 
        /// Creation fails when the original condition contradicts new boolean condition
        /// 
        /// ViewTarget tells whether MemberPath is in Cquery or SQuery 
        /// 
        private bool TryCreateAdditionalCellWithCondition(Cell originalCell, MemberPath memberToExpand, bool conditionValue, ViewTarget viewTarget, out Cell result) 
        {
            Debug.Assert(originalCell != null);
            Debug.Assert(memberToExpand != null);
            result = null; 

            //Create required structures 
            MemberPath leftExtent = originalCell.GetLeftQuery(viewTarget).SourceExtentMemberPath; 
            MemberPath rightExtent = originalCell.GetRightQuery(viewTarget).SourceExtentMemberPath;
            MemberPath leftConditionMemberNode = new MemberPath(leftExtent, memberToExpand.LeafEdmMember); 

            //Now for the given left-side projected member, find corresponding right-side member that it is mapped to
            int indexOfBooLMemberInProjection = originalCell.GetLeftQuery(viewTarget).GetProjectedMembers().TakeWhile(path => !path.Equals(memberToExpand)).Count();
            MemberProjectedSlot rightConditionMemberSlot = ((MemberProjectedSlot)originalCell.GetRightQuery(viewTarget).ProjectedSlotAt(indexOfBooLMemberInProjection)); 
            MemberPath rightSidePath = rightConditionMemberSlot.MemberPath;
 
            List leftSlots = new List(); 
            List rightSlots = new List();
 

            //Check for impossible conditions (otehrwise we get inaccurate pre-validation errors)
            ScalarConstant negatedCondition = new ScalarConstant(!conditionValue);
 
            if (originalCell.GetLeftQuery(viewTarget).Conditions
                    .Where(restriction => restriction.RestrictedMemberSlot.MemberPath.Equals(leftConditionMemberNode)) 
                    .Where(restriction => restriction.Domain.Values.Contains(negatedCondition)).Any() 
                || originalCell.GetRightQuery(viewTarget).Conditions
                    .Where(restriction => restriction.RestrictedMemberSlot.MemberPath.Equals(rightSidePath)) 
                    .Where(restriction => restriction.Domain.Values.Contains(negatedCondition)).Any())
            {
                return false;
            } 
            //End check
 
            //Create Projected Slots 
            // Map all slots in original cell (not just keys) because some may be required (non nullable and no default)
            // and others may have not_null condition so MUST be projected. Rely on the user doing the right thing, otherwise 
            // they will get the error message anyway
            for (int i = 0; i < originalCell.GetLeftQuery(viewTarget).NumProjectedSlots; i++)
            {
                leftSlots.Add(originalCell.GetLeftQuery(viewTarget).ProjectedSlotAt(i)); 
            }
 
            for (int i = 0; i < originalCell.GetRightQuery(viewTarget).NumProjectedSlots; i++) 
            {
                rightSlots.Add(originalCell.GetRightQuery(viewTarget).ProjectedSlotAt(i)); 
            }

            //Create condition boolena expressions
            BoolExpression leftQueryWhereClause = BoolExpression.CreateLiteral(new ScalarRestriction(leftConditionMemberNode, new ScalarConstant(conditionValue)), null); 
            leftQueryWhereClause = BoolExpression.CreateAnd(originalCell.GetLeftQuery(viewTarget).WhereClause, leftQueryWhereClause);
 
            MemberPath rightConditionMemberNode = new MemberPath(rightExtent, rightSidePath.LeafEdmMember); 
            BoolExpression rightQueryWhereClause = BoolExpression.CreateLiteral(new ScalarRestriction(rightConditionMemberNode, new ScalarConstant(conditionValue)), null);
            rightQueryWhereClause = BoolExpression.CreateAnd(originalCell.GetRightQuery(viewTarget).WhereClause, rightQueryWhereClause); 


            //Create additional Cells
            CellQuery rightQuery = new CellQuery(rightSlots, rightQueryWhereClause, rightExtent, originalCell.GetRightQuery(viewTarget).SelectDistinctFlag); 
            CellQuery leftQuery = new CellQuery(leftSlots, leftQueryWhereClause, leftExtent, originalCell.GetLeftQuery(viewTarget).SelectDistinctFlag);
 
            Cell newCell; 
            if (viewTarget == ViewTarget.UpdateView)
            { 
                newCell = Cell.CreateCS(rightQuery, leftQuery, originalCell.CellLabel, m_currentCellNumber);
            }
            else
            { 
                newCell = Cell.CreateCS(leftQuery, rightQuery, originalCell.CellLabel, m_currentCellNumber);
            } 
 
            m_currentCellNumber++;
            result = newCell; 
            return true;
        }

        // effects: Given the metadata information for a container in 
        // containerMap, generate the cells for it and modify cells to
        // contain the newly-generated cells 
        private void ExtractCells(List cells) 
        {
            // extract entity mappings, i.e., for CPerson1, COrder1, etc 
            foreach (StorageSetMapping extentMap in m_containerMapping.AllSetMaps)
            {

                // Get each type map in an entity set mapping, i.e., for 
                // CPerson, CCustomer, etc in CPerson1
                foreach (StorageTypeMapping typeMap in extentMap.TypeMappings) 
                { 

                    StorageEntityTypeMapping entityTypeMap = typeMap as StorageEntityTypeMapping; 
                    Debug.Assert(entityTypeMap != null ||
                                 typeMap is StorageAssociationTypeMapping, "Invalid typemap");

                    // A set for all the types in this type mapping 
                    Set allTypes = new Set();
 
 
                    if (entityTypeMap != null)
                    { 
                        // Gather a set of all explicit types for an entity
                        // type mapping in allTypes. Note that we do not have
                        // subtyping in composition sets and association sets
                        allTypes.AddRange(entityTypeMap.Types); 
                        foreach (EdmType type in entityTypeMap.IsOfTypes)
                        { 
                            IEnumerable typeAndSubTypes = MetadataHelper.GetTypeAndSubtypesOf(type, m_containerMapping.StorageMappingItemCollection.EdmItemCollection, false /*includeAbstractTypes*/); 
                            allTypes.AddRange(typeAndSubTypes);
                        } 
                    }

                    EntitySetBase extent = extentMap.Set;
                    Debug.Assert(extent != null, "Extent map for a null extent or type of extentMap.Exent " + 
                                 "is not Extent");
 
                    // For each table mapping for the type mapping, we create cells 
                    foreach (StorageMappingFragment fragmentMap in typeMap.MappingFragments)
                    { 
                        ExtractCellsFromTableFragment(extent, fragmentMap, allTypes, cells);
                    }
                }
            } 
        }
 
        // effects: Given an extent's ("extent") table fragment that is 
        // contained inside typeMap, determine the cells that need to be
        // created and add them to cells 
        // allTypes corresponds to all the different types that the type map
        // represents -- this parameter has something useful only if extent
        // is an entity set
        private void ExtractCellsFromTableFragment(EntitySetBase extent, StorageMappingFragment fragmentMap, 
                                                   Set allTypes, List cells)
        { 
 
            // create C-query components
            MemberPath cRootExtent = new MemberPath(extent); 
            BoolExpression cQueryWhereClause = BoolExpression.True;
            List cSlots = new List();

            if (allTypes.Count > 0) 
            {
                // Create a type condition for the extent, i.e., "extent in allTypes" 
                cQueryWhereClause = BoolExpression.CreateLiteral(new TypeRestriction(cRootExtent, allTypes), null); 
            }
 
            // create S-query components
            MemberPath sRootExtent = new MemberPath(fragmentMap.TableSet);
            BoolExpression sQueryWhereClause = BoolExpression.True;
            List sSlots = new List(); 

            // Association or entity set 
            // Add the properties and the key properties to a list and 
            // then process them in ExtractProperties
            ExtractProperties(fragmentMap.AllProperties, cRootExtent, cSlots, ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause); 

            // limitation of MSL API: cannot assign constant values to table columns
            CellQuery cQuery = new CellQuery(cSlots, cQueryWhereClause, cRootExtent, CellQuery.SelectDistinct.No /*no distinct flag*/);
            CellQuery sQuery = new CellQuery(sSlots, sQueryWhereClause, sRootExtent, 
                                        fragmentMap.IsSQueryDistinct ? CellQuery.SelectDistinct.Yes : CellQuery.SelectDistinct.No);
 
            StorageMappingFragment fragmentInfo = fragmentMap as StorageMappingFragment; 
            Debug.Assert((fragmentInfo != null), "CSMappingFragment should support Line Info");
            CellLabel label = new CellLabel(fragmentInfo); 
            Cell cell = Cell.CreateCS(cQuery, sQuery, label, m_currentCellNumber);
            m_currentCellNumber++;
            cells.Add(cell);
        } 

        // requires: "properties" corresponds to all the properties that are 
        // inside cNode.Value, e.g., cNode corresponds to an extent Person, 
        // properties contains all the properties inside Person (recursively)
        // effects: Given C-side and S-side Cell Query for a cell, generates 
        // the projected slots on both sides corresponding to
        // properties. Also updates the C-side whereclause corresponding to
        // discriminator properties on the C-side, e.g, isHighPriority
        private void ExtractProperties(IEnumerable properties, 
                                       MemberPath cNode, List cSlots,
                                       ref BoolExpression cQueryWhereClause, 
                                       MemberPath sRootExtent, 
                                       List sSlots,
                                       ref BoolExpression sQueryWhereClause) 
        {
            // For each property mapping, we add an entry to the C and S cell queries
            foreach (StoragePropertyMapping propMap in properties)
            { 

                StorageScalarPropertyMapping scalarPropMap = propMap as StorageScalarPropertyMapping; 
                StorageComplexPropertyMapping complexPropMap = propMap as StorageComplexPropertyMapping; 
                StorageEndPropertyMapping associationEndPropertypMap = propMap as StorageEndPropertyMapping;
                StorageConditionPropertyMapping conditionMap = propMap as StorageConditionPropertyMapping; 

                Debug.Assert(scalarPropMap != null ||
                             complexPropMap != null ||
                             associationEndPropertypMap != null || 
                             conditionMap != null, "Unimplemented property mapping");
 
                if (scalarPropMap != null) 
                {
                    Debug.Assert(scalarPropMap.ColumnProperty != null, "ColumnMember for a Scalar Property can not be null"); 
                    // Add an attribute node to node

                    MemberPath cAttributeNode = new MemberPath(cNode, scalarPropMap.EdmProperty);
                    // Add a column (attribute) node the sQuery 
                    // unlike the C side, there is no nesting. Hence we
                    // did not need an internal node 
                    MemberPath sAttributeNode = new MemberPath(sRootExtent, scalarPropMap.ColumnProperty); 
                    cSlots.Add(new MemberProjectedSlot(cAttributeNode));
                    sSlots.Add(new MemberProjectedSlot(sAttributeNode)); 
                }
                // Note: S-side constants are not allowed since they can cause
                // problems -- for example, if such a cell says 5 for the
                // third field, we cannot guarantee the fact that an 
                // application may not set that field to 7 in the C-space
 
                // Check if the property mapping is for an complex types 
                if (complexPropMap != null)
                { 
                    foreach (StorageComplexTypeMapping complexTypeMap in complexPropMap.TypeMappings)
                    {
                        // Create a node for the complex type property and call recursively
                        MemberPath complexMemberNode = new MemberPath(cNode, complexPropMap.EdmProperty); 
                        //Get the list of types that this type map represents
                        Set allTypes = new Set(); 
                        // Gather a set of all explicit types for an entity 
                        // type mapping in allTypes.
                        IEnumerable exactTypes = Helpers.AsSuperTypeList(complexTypeMap.Types); 
                        allTypes.AddRange(exactTypes);
                        foreach (EdmType type in complexTypeMap.IsOfTypes)
                        {
                            allTypes.AddRange(MetadataHelper.GetTypeAndSubtypesOf(type, m_containerMapping.StorageMappingItemCollection.EdmItemCollection, false /*includeAbstractTypes*/)); 
                        }
                        BoolExpression complexInTypes = BoolExpression.CreateLiteral(new TypeRestriction(complexMemberNode, allTypes), null); 
                        cQueryWhereClause = BoolExpression.CreateAnd(cQueryWhereClause, complexInTypes); 
                        // Now extract the properties of the complex type
                        // (which could have other complex types) 
                        ExtractProperties(complexTypeMap.AllProperties, complexMemberNode, cSlots,
                                          ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause);
                    }
                } 

                // Check if the property mapping is for an associaion 
                if (associationEndPropertypMap != null) 
                {
                    // create join tree node representing this relation end 
                    MemberPath associationEndNode = new MemberPath(cNode, associationEndPropertypMap.EndMember);
                    // call recursively
                    ExtractProperties(associationEndPropertypMap.Properties, associationEndNode, cSlots,
                                      ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause); 
                }
 
                //Check if the this is a condition and add it to the Where clause 
                if (conditionMap != null)
                { 
                    if (conditionMap.ColumnProperty != null)
                    {
                        //Produce a Condition Expression for the Condition Map.
                        BoolExpression conditionExpression = GetConditionExpression(sRootExtent, conditionMap); 
                        //Add the condition expression to the exisiting S side Where clause using an "And"
                        sQueryWhereClause = BoolExpression.CreateAnd(sQueryWhereClause, conditionExpression); 
                    } 
                    else
                    { 
                        Debug.Assert(conditionMap.EdmProperty != null);
                        //Produce a Condition Expression for the Condition Map.
                        BoolExpression conditionExpression = GetConditionExpression(cNode, conditionMap);
                        //Add the condition expression to the exisiting C side Where clause using an "And" 
                        cQueryWhereClause = BoolExpression.CreateAnd(cQueryWhereClause, conditionExpression);
                    } 
 
                }
            } 
        }

        /// 
        /// Takes in a JoinTreeNode and a Contition Property Map and creates an BoolExpression 
        /// for the Condition Map.
        ///  
        ///  
        /// 
        ///  
        private static BoolExpression GetConditionExpression(MemberPath member, StorageConditionPropertyMapping conditionMap)
        {
            //Get the member for which the condition is being specified
            EdmMember conditionMember = (conditionMap.ColumnProperty != null) ? conditionMap.ColumnProperty : conditionMap.EdmProperty; 

            MemberPath conditionMemberNode = new MemberPath(member, conditionMember); 
            //Check if this is a IsNull condition 
            MemberRestriction conditionExpression = null;
            if (conditionMap.IsNull.HasValue) 
            {
                // for conditions on scalars, create NodeValue nodes, otherwise NodeType
                Constant conditionConstant = (true == conditionMap.IsNull.Value) ? Constant.Null : Constant.NotNull;
                if (true == MetadataHelper.IsNonRefSimpleMember(conditionMember)) 
                {
                    conditionExpression = new ScalarRestriction(conditionMemberNode, conditionConstant); 
                } 
                else
                { 
                    conditionExpression = new TypeRestriction(conditionMemberNode, conditionConstant);
                }
            }
            else 
            {
                TypeUsage conditionMemberTypeUsage = (conditionMap.ColumnProperty != null) ? conditionMap.ColumnProperty.TypeUsage : conditionMap.EdmProperty.TypeUsage; 
                conditionExpression = new ScalarRestriction(conditionMemberNode, conditionMap.Value, conditionMemberTypeUsage); 
            }
 
            Debug.Assert(conditionExpression != null);

            return BoolExpression.CreateLiteral(conditionExpression, null);
        } 

        private static bool IsBooleanMember(MemberPath path) 
        { 
            PrimitiveType primitive = path.EdmType as PrimitiveType;
            return (primitive != null && primitive.PrimitiveTypeKind == PrimitiveTypeKind.Boolean); 
        }
        #endregion

        #region String methods 
        internal override void ToCompactString(System.Text.StringBuilder builder)
        { 
            builder.Append("CellCreator"); // No state to really show i.e., m_maps 
        }
 
        #endregion

    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Common.Utils; 
using System.Data.Mapping.ViewGeneration.Structures;
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.Utils;
using System.Diagnostics; 
using System.Data.Metadata.Edm;
using System.Linq; 
 
namespace System.Data.Mapping.ViewGeneration
{ 


    // A class that handles creation of cells from the meta data information
    internal class CellCreator : InternalBase 
    {
 
        #region Constructors 
        // effects: Creates a cell creator object for an entity container's
        // mappings (specified in "maps") 
        internal CellCreator(StorageEntityContainerMapping containerMapping)
        {
            m_containerMapping = containerMapping;
            m_identifiers = new CqlIdentifiers(); 
        }
        #endregion 
 
        #region Fields
        // The mappings from the metadata for different containers 
        private StorageEntityContainerMapping m_containerMapping;
        private int m_currentCellNumber;
        private CqlIdentifiers m_identifiers;
        // Keep track of all the identifiers to prevent clashes with _from0, 
        // _from1, T, T1, etc
        // Keep track of names of 
        // * Entity Containers 
        // * Extent names
        // * Entity Types 
        // * Complex Types
        // * Properties
        // * Roles
        #endregion 

        #region Properties 
        // effects: Returns the set of identifiers used in this 
        internal CqlIdentifiers Identifiers
        { 
            get { return m_identifiers; }
        }
        #endregion
 
        #region External methods
        // effects: Generates the cells for all the entity containers 
        // specified in this. The generated cells are geared for query view generation 
        internal List GenerateCells(ConfigViewGenerator config)
        { 
            List cells = new List();

            if (config.IsNormalTracing)
            { 
                m_containerMapping.Print(0);
            } 
            // Get the cells from the entity container metadata 
            ExtractCells(cells);
 
            ExpandCells(cells);

            // Get the identifiers from the cells
            m_identifiers.AddIdentifier(m_containerMapping.EdmEntityContainer.Name); 
            m_identifiers.AddIdentifier(m_containerMapping.StorageEntityContainer.Name);
            foreach (Cell cell in cells) 
            { 
                cell.GetIdentifiers(m_identifiers);
            } 

            return cells;
        }
        #endregion 

        #region Private Methods 
        ///  
        /// Boolean members have a closed domain and are enumerated when domains are established i.e. (T, F) instead of (notNull).
        /// Query Rewriting is exercised over every domain of the condition member. If the member contains not_null condition 
        /// for example, it cannot generate a view for partitions (member=T), (Member=F). For this reason we need to expand the cells
        /// in a predefined situation (below) to include sub-fragments mapping individual elements of the closed domain.
        /// Enums (a planned feature) need to be handled in a similar fashion.
        /// 
        /// Find booleans that are projected with a not_null condition
        /// Expand ALL cells where they are projected. Why? See Unit Test case NullabilityConditionOnBoolean5.es 
        /// Validation will fail because it will not be able to validate rewritings for partitions on the 'other' cells. 
        /// 
        private void ExpandCells(List cells) 
        {
            var sSideMembersToBeExpanded = new Set();

            foreach (Cell cell in cells) 
            {
                //Find Projected members that are Boolean AND are mentioned in the Where clause with not_null condition 
                foreach (var memberToExpand in cell.SQuery.GetProjectedMembers() 
                                            .Where(member => IsBooleanMember(member))
                                            .Where(boolMember => cell.SQuery.GetConjunctsFromWhereClause() 
                                                                    .Where(restriction => restriction.Domain.Values.Contains(Constant.NotNull))
                                                                    .Select(restriction => restriction.RestrictedMemberSlot.MemberPath).Contains(boolMember)))
                {
                    sSideMembersToBeExpanded.Add(memberToExpand); 
                }
            } 
 
            //Foreach s-side members, find all c-side members it is mapped to
            //  We need these because we need to expand all cells where the  boolean candidate is projected or mapped member is projected, e.g: 
            //   (1) C[id, cdisc] WHERE d=true   <=>   T1[id, sdisc] WHERE sdisc=NOTNULL
            //   (2) C[id, cdisc] WHERE d=false  <=>   T2[id, sdisc]
            //  Here we need to know that because of T1.sdisc, we need to expand T2.sdisc.
            //  This is done by tracking cdisc, and then seeing in cell 2 that it is mapped to T2.sdisc 

            var cSideMembersForSSideExpansionCandidates = new Dictionary>(); 
            foreach (Cell cell in cells) 
            {
                foreach (var sSideMemberToExpand in sSideMembersToBeExpanded) 
                {
                    var cSideMembers = cell.SQuery.GetProjectedPositions(sSideMemberToExpand).Select(pos => ((MemberProjectedSlot)cell.CQuery.ProjectedSlotAt(pos)).MemberPath);

                    Set cSidePaths = null; 
                    if (!cSideMembersForSSideExpansionCandidates.TryGetValue(sSideMemberToExpand, out cSidePaths))
                    { 
                        cSidePaths = new Set(); 
                        cSideMembersForSSideExpansionCandidates[sSideMemberToExpand] = cSidePaths;
                    } 

                    cSidePaths.AddRange(cSideMembers);
                }
            } 

            // Expand cells that project members collected earlier with T/F conditiions 
            foreach (Cell cell in cells.ToArray()) 
            {
                //Each member gets its own expansion. Including multiple condition candidates in one SQuery 
                // "... <=> T[..] WHERE a=notnull AND b=notnull" means a and b get their own independent expansions
                // Note: this is not a cross-product
                foreach (var memberToExpand in sSideMembersToBeExpanded)
                { 
                    var mappedCSideMembers = cSideMembersForSSideExpansionCandidates[memberToExpand];
 
                    //Check if member is projected in this cell. 
                    if (cell.SQuery.GetProjectedMembers().Contains(memberToExpand))
                    { 
                        // Creationg additional cel can fail when the condition to be appended contradicts existing condition in the CellQuery
                        // We don't add contradictions because they seem to cause unrelated problems in subsequent validation routines
                        Cell resultCell = null;
                        if (TryCreateAdditionalCellWithCondition(cell, memberToExpand, true  /*condition value*/, ViewTarget.UpdateView /*s-side member*/, out resultCell)) 
                        {
                            cells.Add(resultCell); 
                        } 
                        if (TryCreateAdditionalCellWithCondition(cell, memberToExpand, false /*condition value*/, ViewTarget.UpdateView /*s-side member*/, out resultCell))
                        { 
                            cells.Add(resultCell);
                        }
                    }
                    else 
                    {  //If the s-side member is not projected, see if the mapped C-side member(s) is projected
                        foreach (var cMemberToExpand in cell.CQuery.GetProjectedMembers().Intersect(mappedCSideMembers)) 
                        { 
                            Cell resultCell = null;
                            if (TryCreateAdditionalCellWithCondition(cell, cMemberToExpand, true  /*condition value*/, ViewTarget.QueryView /*c-side member*/, out resultCell)) 
                            {
                                cells.Add(resultCell);
                            }
 
                            if (TryCreateAdditionalCellWithCondition(cell, cMemberToExpand, false /*condition value*/, ViewTarget.QueryView /*c-side member*/, out resultCell))
                            { 
                                cells.Add(resultCell); 
                            }
                        } 
                    }
                }
            }
 
        }
 
 

        ///  
        /// Given a cell, a member and a boolean condition on that member, creates additional cell
        /// which with the specified restriction on the member in addition to original condition.
        /// e.i conjunction of original condition AND member in newCondition
        /// 
        /// Creation fails when the original condition contradicts new boolean condition
        /// 
        /// ViewTarget tells whether MemberPath is in Cquery or SQuery 
        /// 
        private bool TryCreateAdditionalCellWithCondition(Cell originalCell, MemberPath memberToExpand, bool conditionValue, ViewTarget viewTarget, out Cell result) 
        {
            Debug.Assert(originalCell != null);
            Debug.Assert(memberToExpand != null);
            result = null; 

            //Create required structures 
            MemberPath leftExtent = originalCell.GetLeftQuery(viewTarget).SourceExtentMemberPath; 
            MemberPath rightExtent = originalCell.GetRightQuery(viewTarget).SourceExtentMemberPath;
            MemberPath leftConditionMemberNode = new MemberPath(leftExtent, memberToExpand.LeafEdmMember); 

            //Now for the given left-side projected member, find corresponding right-side member that it is mapped to
            int indexOfBooLMemberInProjection = originalCell.GetLeftQuery(viewTarget).GetProjectedMembers().TakeWhile(path => !path.Equals(memberToExpand)).Count();
            MemberProjectedSlot rightConditionMemberSlot = ((MemberProjectedSlot)originalCell.GetRightQuery(viewTarget).ProjectedSlotAt(indexOfBooLMemberInProjection)); 
            MemberPath rightSidePath = rightConditionMemberSlot.MemberPath;
 
            List leftSlots = new List(); 
            List rightSlots = new List();
 

            //Check for impossible conditions (otehrwise we get inaccurate pre-validation errors)
            ScalarConstant negatedCondition = new ScalarConstant(!conditionValue);
 
            if (originalCell.GetLeftQuery(viewTarget).Conditions
                    .Where(restriction => restriction.RestrictedMemberSlot.MemberPath.Equals(leftConditionMemberNode)) 
                    .Where(restriction => restriction.Domain.Values.Contains(negatedCondition)).Any() 
                || originalCell.GetRightQuery(viewTarget).Conditions
                    .Where(restriction => restriction.RestrictedMemberSlot.MemberPath.Equals(rightSidePath)) 
                    .Where(restriction => restriction.Domain.Values.Contains(negatedCondition)).Any())
            {
                return false;
            } 
            //End check
 
            //Create Projected Slots 
            // Map all slots in original cell (not just keys) because some may be required (non nullable and no default)
            // and others may have not_null condition so MUST be projected. Rely on the user doing the right thing, otherwise 
            // they will get the error message anyway
            for (int i = 0; i < originalCell.GetLeftQuery(viewTarget).NumProjectedSlots; i++)
            {
                leftSlots.Add(originalCell.GetLeftQuery(viewTarget).ProjectedSlotAt(i)); 
            }
 
            for (int i = 0; i < originalCell.GetRightQuery(viewTarget).NumProjectedSlots; i++) 
            {
                rightSlots.Add(originalCell.GetRightQuery(viewTarget).ProjectedSlotAt(i)); 
            }

            //Create condition boolena expressions
            BoolExpression leftQueryWhereClause = BoolExpression.CreateLiteral(new ScalarRestriction(leftConditionMemberNode, new ScalarConstant(conditionValue)), null); 
            leftQueryWhereClause = BoolExpression.CreateAnd(originalCell.GetLeftQuery(viewTarget).WhereClause, leftQueryWhereClause);
 
            MemberPath rightConditionMemberNode = new MemberPath(rightExtent, rightSidePath.LeafEdmMember); 
            BoolExpression rightQueryWhereClause = BoolExpression.CreateLiteral(new ScalarRestriction(rightConditionMemberNode, new ScalarConstant(conditionValue)), null);
            rightQueryWhereClause = BoolExpression.CreateAnd(originalCell.GetRightQuery(viewTarget).WhereClause, rightQueryWhereClause); 


            //Create additional Cells
            CellQuery rightQuery = new CellQuery(rightSlots, rightQueryWhereClause, rightExtent, originalCell.GetRightQuery(viewTarget).SelectDistinctFlag); 
            CellQuery leftQuery = new CellQuery(leftSlots, leftQueryWhereClause, leftExtent, originalCell.GetLeftQuery(viewTarget).SelectDistinctFlag);
 
            Cell newCell; 
            if (viewTarget == ViewTarget.UpdateView)
            { 
                newCell = Cell.CreateCS(rightQuery, leftQuery, originalCell.CellLabel, m_currentCellNumber);
            }
            else
            { 
                newCell = Cell.CreateCS(leftQuery, rightQuery, originalCell.CellLabel, m_currentCellNumber);
            } 
 
            m_currentCellNumber++;
            result = newCell; 
            return true;
        }

        // effects: Given the metadata information for a container in 
        // containerMap, generate the cells for it and modify cells to
        // contain the newly-generated cells 
        private void ExtractCells(List cells) 
        {
            // extract entity mappings, i.e., for CPerson1, COrder1, etc 
            foreach (StorageSetMapping extentMap in m_containerMapping.AllSetMaps)
            {

                // Get each type map in an entity set mapping, i.e., for 
                // CPerson, CCustomer, etc in CPerson1
                foreach (StorageTypeMapping typeMap in extentMap.TypeMappings) 
                { 

                    StorageEntityTypeMapping entityTypeMap = typeMap as StorageEntityTypeMapping; 
                    Debug.Assert(entityTypeMap != null ||
                                 typeMap is StorageAssociationTypeMapping, "Invalid typemap");

                    // A set for all the types in this type mapping 
                    Set allTypes = new Set();
 
 
                    if (entityTypeMap != null)
                    { 
                        // Gather a set of all explicit types for an entity
                        // type mapping in allTypes. Note that we do not have
                        // subtyping in composition sets and association sets
                        allTypes.AddRange(entityTypeMap.Types); 
                        foreach (EdmType type in entityTypeMap.IsOfTypes)
                        { 
                            IEnumerable typeAndSubTypes = MetadataHelper.GetTypeAndSubtypesOf(type, m_containerMapping.StorageMappingItemCollection.EdmItemCollection, false /*includeAbstractTypes*/); 
                            allTypes.AddRange(typeAndSubTypes);
                        } 
                    }

                    EntitySetBase extent = extentMap.Set;
                    Debug.Assert(extent != null, "Extent map for a null extent or type of extentMap.Exent " + 
                                 "is not Extent");
 
                    // For each table mapping for the type mapping, we create cells 
                    foreach (StorageMappingFragment fragmentMap in typeMap.MappingFragments)
                    { 
                        ExtractCellsFromTableFragment(extent, fragmentMap, allTypes, cells);
                    }
                }
            } 
        }
 
        // effects: Given an extent's ("extent") table fragment that is 
        // contained inside typeMap, determine the cells that need to be
        // created and add them to cells 
        // allTypes corresponds to all the different types that the type map
        // represents -- this parameter has something useful only if extent
        // is an entity set
        private void ExtractCellsFromTableFragment(EntitySetBase extent, StorageMappingFragment fragmentMap, 
                                                   Set allTypes, List cells)
        { 
 
            // create C-query components
            MemberPath cRootExtent = new MemberPath(extent); 
            BoolExpression cQueryWhereClause = BoolExpression.True;
            List cSlots = new List();

            if (allTypes.Count > 0) 
            {
                // Create a type condition for the extent, i.e., "extent in allTypes" 
                cQueryWhereClause = BoolExpression.CreateLiteral(new TypeRestriction(cRootExtent, allTypes), null); 
            }
 
            // create S-query components
            MemberPath sRootExtent = new MemberPath(fragmentMap.TableSet);
            BoolExpression sQueryWhereClause = BoolExpression.True;
            List sSlots = new List(); 

            // Association or entity set 
            // Add the properties and the key properties to a list and 
            // then process them in ExtractProperties
            ExtractProperties(fragmentMap.AllProperties, cRootExtent, cSlots, ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause); 

            // limitation of MSL API: cannot assign constant values to table columns
            CellQuery cQuery = new CellQuery(cSlots, cQueryWhereClause, cRootExtent, CellQuery.SelectDistinct.No /*no distinct flag*/);
            CellQuery sQuery = new CellQuery(sSlots, sQueryWhereClause, sRootExtent, 
                                        fragmentMap.IsSQueryDistinct ? CellQuery.SelectDistinct.Yes : CellQuery.SelectDistinct.No);
 
            StorageMappingFragment fragmentInfo = fragmentMap as StorageMappingFragment; 
            Debug.Assert((fragmentInfo != null), "CSMappingFragment should support Line Info");
            CellLabel label = new CellLabel(fragmentInfo); 
            Cell cell = Cell.CreateCS(cQuery, sQuery, label, m_currentCellNumber);
            m_currentCellNumber++;
            cells.Add(cell);
        } 

        // requires: "properties" corresponds to all the properties that are 
        // inside cNode.Value, e.g., cNode corresponds to an extent Person, 
        // properties contains all the properties inside Person (recursively)
        // effects: Given C-side and S-side Cell Query for a cell, generates 
        // the projected slots on both sides corresponding to
        // properties. Also updates the C-side whereclause corresponding to
        // discriminator properties on the C-side, e.g, isHighPriority
        private void ExtractProperties(IEnumerable properties, 
                                       MemberPath cNode, List cSlots,
                                       ref BoolExpression cQueryWhereClause, 
                                       MemberPath sRootExtent, 
                                       List sSlots,
                                       ref BoolExpression sQueryWhereClause) 
        {
            // For each property mapping, we add an entry to the C and S cell queries
            foreach (StoragePropertyMapping propMap in properties)
            { 

                StorageScalarPropertyMapping scalarPropMap = propMap as StorageScalarPropertyMapping; 
                StorageComplexPropertyMapping complexPropMap = propMap as StorageComplexPropertyMapping; 
                StorageEndPropertyMapping associationEndPropertypMap = propMap as StorageEndPropertyMapping;
                StorageConditionPropertyMapping conditionMap = propMap as StorageConditionPropertyMapping; 

                Debug.Assert(scalarPropMap != null ||
                             complexPropMap != null ||
                             associationEndPropertypMap != null || 
                             conditionMap != null, "Unimplemented property mapping");
 
                if (scalarPropMap != null) 
                {
                    Debug.Assert(scalarPropMap.ColumnProperty != null, "ColumnMember for a Scalar Property can not be null"); 
                    // Add an attribute node to node

                    MemberPath cAttributeNode = new MemberPath(cNode, scalarPropMap.EdmProperty);
                    // Add a column (attribute) node the sQuery 
                    // unlike the C side, there is no nesting. Hence we
                    // did not need an internal node 
                    MemberPath sAttributeNode = new MemberPath(sRootExtent, scalarPropMap.ColumnProperty); 
                    cSlots.Add(new MemberProjectedSlot(cAttributeNode));
                    sSlots.Add(new MemberProjectedSlot(sAttributeNode)); 
                }
                // Note: S-side constants are not allowed since they can cause
                // problems -- for example, if such a cell says 5 for the
                // third field, we cannot guarantee the fact that an 
                // application may not set that field to 7 in the C-space
 
                // Check if the property mapping is for an complex types 
                if (complexPropMap != null)
                { 
                    foreach (StorageComplexTypeMapping complexTypeMap in complexPropMap.TypeMappings)
                    {
                        // Create a node for the complex type property and call recursively
                        MemberPath complexMemberNode = new MemberPath(cNode, complexPropMap.EdmProperty); 
                        //Get the list of types that this type map represents
                        Set allTypes = new Set(); 
                        // Gather a set of all explicit types for an entity 
                        // type mapping in allTypes.
                        IEnumerable exactTypes = Helpers.AsSuperTypeList(complexTypeMap.Types); 
                        allTypes.AddRange(exactTypes);
                        foreach (EdmType type in complexTypeMap.IsOfTypes)
                        {
                            allTypes.AddRange(MetadataHelper.GetTypeAndSubtypesOf(type, m_containerMapping.StorageMappingItemCollection.EdmItemCollection, false /*includeAbstractTypes*/)); 
                        }
                        BoolExpression complexInTypes = BoolExpression.CreateLiteral(new TypeRestriction(complexMemberNode, allTypes), null); 
                        cQueryWhereClause = BoolExpression.CreateAnd(cQueryWhereClause, complexInTypes); 
                        // Now extract the properties of the complex type
                        // (which could have other complex types) 
                        ExtractProperties(complexTypeMap.AllProperties, complexMemberNode, cSlots,
                                          ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause);
                    }
                } 

                // Check if the property mapping is for an associaion 
                if (associationEndPropertypMap != null) 
                {
                    // create join tree node representing this relation end 
                    MemberPath associationEndNode = new MemberPath(cNode, associationEndPropertypMap.EndMember);
                    // call recursively
                    ExtractProperties(associationEndPropertypMap.Properties, associationEndNode, cSlots,
                                      ref cQueryWhereClause, sRootExtent, sSlots, ref sQueryWhereClause); 
                }
 
                //Check if the this is a condition and add it to the Where clause 
                if (conditionMap != null)
                { 
                    if (conditionMap.ColumnProperty != null)
                    {
                        //Produce a Condition Expression for the Condition Map.
                        BoolExpression conditionExpression = GetConditionExpression(sRootExtent, conditionMap); 
                        //Add the condition expression to the exisiting S side Where clause using an "And"
                        sQueryWhereClause = BoolExpression.CreateAnd(sQueryWhereClause, conditionExpression); 
                    } 
                    else
                    { 
                        Debug.Assert(conditionMap.EdmProperty != null);
                        //Produce a Condition Expression for the Condition Map.
                        BoolExpression conditionExpression = GetConditionExpression(cNode, conditionMap);
                        //Add the condition expression to the exisiting C side Where clause using an "And" 
                        cQueryWhereClause = BoolExpression.CreateAnd(cQueryWhereClause, conditionExpression);
                    } 
 
                }
            } 
        }

        /// 
        /// Takes in a JoinTreeNode and a Contition Property Map and creates an BoolExpression 
        /// for the Condition Map.
        ///  
        ///  
        /// 
        ///  
        private static BoolExpression GetConditionExpression(MemberPath member, StorageConditionPropertyMapping conditionMap)
        {
            //Get the member for which the condition is being specified
            EdmMember conditionMember = (conditionMap.ColumnProperty != null) ? conditionMap.ColumnProperty : conditionMap.EdmProperty; 

            MemberPath conditionMemberNode = new MemberPath(member, conditionMember); 
            //Check if this is a IsNull condition 
            MemberRestriction conditionExpression = null;
            if (conditionMap.IsNull.HasValue) 
            {
                // for conditions on scalars, create NodeValue nodes, otherwise NodeType
                Constant conditionConstant = (true == conditionMap.IsNull.Value) ? Constant.Null : Constant.NotNull;
                if (true == MetadataHelper.IsNonRefSimpleMember(conditionMember)) 
                {
                    conditionExpression = new ScalarRestriction(conditionMemberNode, conditionConstant); 
                } 
                else
                { 
                    conditionExpression = new TypeRestriction(conditionMemberNode, conditionConstant);
                }
            }
            else 
            {
                TypeUsage conditionMemberTypeUsage = (conditionMap.ColumnProperty != null) ? conditionMap.ColumnProperty.TypeUsage : conditionMap.EdmProperty.TypeUsage; 
                conditionExpression = new ScalarRestriction(conditionMemberNode, conditionMap.Value, conditionMemberTypeUsage); 
            }
 
            Debug.Assert(conditionExpression != null);

            return BoolExpression.CreateLiteral(conditionExpression, null);
        } 

        private static bool IsBooleanMember(MemberPath path) 
        { 
            PrimitiveType primitive = path.EdmType as PrimitiveType;
            return (primitive != null && primitive.PrimitiveTypeKind == PrimitiveTypeKind.Boolean); 
        }
        #endregion

        #region String methods 
        internal override void ToCompactString(System.Text.StringBuilder builder)
        { 
            builder.Append("CellCreator"); // No state to really show i.e., m_maps 
        }
 
        #endregion

    }
} 

// 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