CellQuery.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / Structures / CellQuery.cs / 1305376 / CellQuery.cs

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

using System.Data.Common.Utils; 
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.Validation;
using System.Text;
using System.Diagnostics; 
using System.Collections.ObjectModel;
using System.Data.Mapping.ViewGeneration.Utils; 
using System.Data.Mapping.ViewGeneration.CqlGeneration; 
using System.Data.Metadata.Edm;
using System.Linq; 

namespace System.Data.Mapping.ViewGeneration.Structures
{
 
    using AttributeSet = Set;
    using System.Data.Entity; 
 
    // This class stores the C or S query. For example,
    // (C) SELECT (p type Person) AS D1, p.pid, p.name FROM p in P WHERE D1 
    // (S) SELECT True AS D1, pid, name FROM SPerson WHERE D1
    //
    // The cell query is stored in a "factored" manner for ease of
    // cell-merging and cell manipulation. It contains: 
    // * Projection: A sequence of slots and a sequence of boolean slots (one
    //   for each cell in the extent) 
    // * A From part represented as a Join tree 
    // * A where clause
    internal class CellQuery : InternalBase 
    {


        #region Fields 
        // Whether query has a 'SELECT DISTINCT' on top
        internal enum SelectDistinct 
        { 
            Yes,
            No 
        }

        // The boolean expressions that essentially capture the type information
        // Fixed-size list; NULL in the list means 'unused' 
        private List m_boolExprs;
        // The fields including the key fields 
        // May contain NULLs - means 'not in the projection' 
        private ProjectedSlot[] m_projectedSlots;
        // where clause: An expression formed using the boolExprs 
        private BoolExpression m_whereClause;
        private BoolExpression m_originalWhereClause; // m_originalWhereClause is not changed

        private SelectDistinct m_selectDistinct; 
        // The from part of the query
        private MemberPath m_extentMemberPath; 
        // The basic cell relation for all slots in this 
        private BasicCellRelation m_basicCellRelation;
        #endregion 


        #region Constructors
        // effects: Creates a cell query with the given projection (slots), 
        // from part (joinTreeRoot) and the predicate (whereClause)
        // Used for cell creation 
        internal CellQuery(List slots, BoolExpression whereClause, MemberPath rootMember, SelectDistinct eliminateDuplicates) 
            : this(slots.ToArray(), whereClause, new List(), eliminateDuplicates, rootMember)
        { 
        }


 
        // effects: Given all the fields, just sets them.
        internal CellQuery(ProjectedSlot[] projectedSlots, 
                          BoolExpression whereClause, 
                          List boolExprs,
                          SelectDistinct elimDupl, MemberPath rootMember) 
        {

            m_boolExprs = boolExprs;
            m_projectedSlots = projectedSlots; 
            m_whereClause = whereClause;
            m_originalWhereClause = whereClause; 
            m_selectDistinct = elimDupl; 
            m_extentMemberPath = rootMember;
        } 

        /// 
        /// Copy Constructor
        ///  
        internal CellQuery(CellQuery source)
        { 
            this.m_basicCellRelation = source.m_basicCellRelation; 
            this.m_boolExprs = source.m_boolExprs;
            this.m_selectDistinct = source.m_selectDistinct; 
            this.m_extentMemberPath = source.m_extentMemberPath;
            this.m_originalWhereClause = source.m_originalWhereClause;
            this.m_projectedSlots = source.m_projectedSlots;
            this.m_whereClause = source.m_whereClause; 
        }
 
        // effects: Given an existing cellquery, makes a new one based on it 
        // but uses the slots as specified with newSlots
        private CellQuery(CellQuery existing, ProjectedSlot[] newSlots) : 
            this(newSlots, existing.m_whereClause, existing.m_boolExprs,
                 existing.m_selectDistinct, existing.m_extentMemberPath)
        {
        } 
        #endregion
 
        #region Properties 

        internal SelectDistinct SelectDistinctFlag 
        {
            get { return m_selectDistinct; }
        }
 
        // effects: Returns the top levelextent corresponding to this cell query
        internal EntitySetBase Extent 
        { 
            get
            { 
                EntitySetBase extent = m_extentMemberPath.Extent as EntitySetBase;
                Debug.Assert(extent != null, "JoinTreeRoot in cellquery must be an extent");
                return extent;
            } 
        }
 
        // effects: Returns the number of slots projected in the query 
        internal int NumProjectedSlots
        { 
            get { return m_projectedSlots.Length; }
        }

        internal ProjectedSlot[] ProjectedSlots 
        {
            get { return m_projectedSlots; } 
        } 

        internal List BoolVars 
        {
            get { return m_boolExprs; }
        }
 
        // effects: Returns the number of boolean expressions projected in the query
        internal int NumBoolVars 
        { 
            get { return m_boolExprs.Count; }
        } 

        internal BoolExpression WhereClause
        {
            get { return m_whereClause; } 
        }
 
        // effects: Returns the root of the join tree 
        internal MemberPath SourceExtentMemberPath
        { 
            get { return m_extentMemberPath; }
        }

        // effects: Returns the relation that contains all the slots present 
        // in this cell query
        internal BasicCellRelation BasicCellRelation 
        { 
            get
            { 
                Debug.Assert(m_basicCellRelation != null, "BasicCellRelation must be created first");
                return m_basicCellRelation;
            }
        } 

        ///  
        /// [WARNING} 
        /// After cell merging boolean expression can (most likely) have disjunctions (OR node)
        /// to represent the condition that a tuple came from either of the merged cells. 
        /// In this case original where clause IS MERGED CLAUSE with OR!!!
        /// So don't call this after merging. It'll throw or debug assert from within GetConjunctsFromWC()
        /// 
        internal IEnumerable Conditions 
        {
            get { return GetConjunctsFromOriginalWhereClause(); } 
        } 

        #endregion 

        #region ProjectedSlots related methods
        // effects: Returns the slotnum projected slot
        internal ProjectedSlot ProjectedSlotAt(int slotNum) 
        {
            Debug.Assert(slotNum < m_projectedSlots.Length, "Slot number too high"); 
            return m_projectedSlots[slotNum]; 
        }
 
        // requires: All slots in this are join tree slots
        // This method is called for an S-side query
        // cQuery is the corresponding C-side query in the cell
        // sourceCell is the original cell for "this" and cQuery 
        // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so,
        // returns an error record about the duplicated slots 
        internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell) 
        {
            // slotMap stores the slots on the S-side and the 
            // C-side properties that it maps to
            KeyToListMap slotMap =
                new KeyToListMap(MemberProjectedSlot.SpecificEqualityComparer);
 
            // Note that this does work for self-association. In the manager
            // employee example, ManagerId and EmployeeId from the SEmployee 
            // table map to the two ends -- Manager.ManagerId and 
            // Employee.EmployeeId in the C Space
 
            for (int i = 0; i < m_projectedSlots.Length; i++)
            {
                ProjectedSlot projectedSlot = m_projectedSlots[i];
                MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot; 
                Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots");
                slotMap.Add(slot, i); 
            } 

            StringBuilder builder = null; 

            // Now determine the entries that have more than one integer per slot
            bool isErrorSituation = false;
 
            foreach (MemberProjectedSlot slot in slotMap.Keys)
            { 
                ReadOnlyCollection indexes = slotMap.ListForKey(slot); 
                Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least");
 
                if (indexes.Count > 1 &&
                    cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false)
                {
                    // The column is mapped to more than one property and it 
                    // failed the "association corresponds to referential
                    // constraints" check 
 
                    isErrorSituation = true;
                    if (builder == null) 
                    {
                        builder = new StringBuilder(System.Data.Entity.Strings.ViewGen_Duplicate_CProperties_0(Extent.Name));
                        builder.AppendLine();
                    } 
                    StringBuilder tmpBuilder = new StringBuilder();
                    for (int i = 0; i < indexes.Count; i++) 
                    { 
                        int index = indexes[i];
                        if (i != 0) 
                        {
                            tmpBuilder.Append(", ");
                        }
                        // The slot must be a JoinTreeSlot. If it isn't it is an internal error 
                        MemberProjectedSlot cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index];
                        tmpBuilder.Append(cSlot.ToUserString()); 
                    } 
                    builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped_1(slot.ToUserString(), tmpBuilder.ToString()));
                } 
            }

            if (false == isErrorSituation)
            { 
                return null;
            } 
 
            ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty);
            return record; 
        }

        // requires: "this" is a query on the C-side
        // and cSideSlotIndexes corresponds to the indexes 
        // (into "this") that the slot is being mapped into
        // cSideSlotIndexes.Count > 1 - that is, a particular column in "this"'s corresponding S-Query 
        // has been mapped to more than one property in "this" 
        //
        // effects: Checks that the multiple mappings on the C-side are 
        // backed by an appropriate Referential constraint
        // If a column is mapped to two properties  in a single cell:
        // (a) Must be an association
        // (b) The two properties must be on opposite ends of the association 
        // (c) The association must have a RI constraint
        // (d) Ordinal[A] == Ordinal[B] in the RI constraint 
        // (c) and (d) can be stated as - the slots are equivalent, i.e., 
        // kept equal via an RI constraint
        private bool AreSlotsEquivalentViaRefConstraints(ReadOnlyCollection cSideSlotIndexes) 
        {

            // Check (a): Must be an association
            AssociationSet assocSet = Extent as AssociationSet; 
            if (assocSet == null)
            { 
                return false; 
            }
 
            // Check (b): The two properties must be on opposite ends of the association
            // There better be exactly two properties!
            Debug.Assert(cSideSlotIndexes.Count > 1, "Method called when no duplicate mapping");
            if (cSideSlotIndexes.Count > 2) 
            {
                return false; 
            } 

            // They better be join tree slots (if they are mapped!) and map to opposite ends 
            MemberProjectedSlot slot0 = (MemberProjectedSlot)m_projectedSlots[cSideSlotIndexes[0]];
            MemberProjectedSlot slot1 = (MemberProjectedSlot)m_projectedSlots[cSideSlotIndexes[1]];

            return slot0.MemberPath.IsEquivalentViaRefConstraint(slot1.MemberPath); 
        }
 
        // requires: The Where clause satisfies the same requirements a GetConjunctsFromWhereClause 
        // effects: For each slot that has a NotNull condition in the where
        // clause, checks if it is projected. If all such slots are 
        // projected, returns null. Else returns an error record
        internal ErrorLog.Record CheckForProjectedNotNullSlots(Cell sourceCell, IEnumerable associationSets)
        {
            StringBuilder builder = new StringBuilder(); 
            bool foundError = false;
 
            foreach (MemberRestriction restriction in Conditions) 
            {
                if (restriction.Domain.ContainsNotNull()) 
                {
                    MemberProjectedSlot slot = MemberProjectedSlot.GetSlotForMember(m_projectedSlots, restriction.RestrictedMemberSlot.MemberPath);
                    if (slot == null) //member with not null condition is not mapped in this extent
                    { 
                        bool missingMapping = true;
                        if(Extent is EntitySet) 
                        { 
                            bool isCQuery = sourceCell.CQuery == this;
                            ViewTarget target = isCQuery ? ViewTarget.QueryView : ViewTarget.UpdateView; 
                            CellQuery rightCellQuery = isCQuery? sourceCell.SQuery : sourceCell.CQuery;

                            //Find out if there is an association mapping but only if the current Not Null condition is on an EntitySet
                            EntitySet rightExtent = rightCellQuery.Extent as EntitySet; 
                            if (rightExtent != null)
                            { 
                                List associations = MetadataHelper.GetAssociationsForEntitySet(rightCellQuery.Extent as EntitySet); 
                                foreach (var association in associations
                                    .Where(association => association.AssociationSetEnds.Where(end => end.EntitySet != rightCellQuery.Extent).First().CorrespondingAssociationEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One)) 
                                {
                                    foreach (var associationCell in associationSets.Where(c => c.GetRightQuery(target).Extent.EdmEquals(association)))
                                    {
                                        if (MemberProjectedSlot.GetSlotForMember(associationCell.GetLeftQuery(target).ProjectedSlots, restriction.RestrictedMemberSlot.MemberPath) != null) 
                                        {
                                            missingMapping = false; 
                                        } 
                                    }
                                } 
                            }
                        }

                        if (missingMapping) 
                        {
                            // condition of NotNull and slot not being projected 
                            builder.AppendLine(System.Data.Entity.Strings.ViewGen_NotNull_No_Projected_Slot_0( 
                                               restriction.RestrictedMemberSlot.MemberPath.PathToString(false)));
                            foundError = true; 
                        }
                    }
                }
            } 
            if (false == foundError)
            { 
                return null; 
            }
            ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NotNullNoProjectedSlot, builder.ToString(), sourceCell, String.Empty); 
            return record;
        }

        internal void FixMissingSlotAsDefaultConstant(int slotNumber, ConstantProjectedSlot slot) 
        {
            Debug.Assert(m_projectedSlots[slotNumber] == null, "Another attempt to plug in a default value"); 
            m_projectedSlots[slotNumber] = slot; 
        }
 
        // requires: projectedSlotMap which contains a mapping of the fields
        // for "this" to integers
        // effects: Align the fields of this cell query using the
        // projectedSlotMap and generates a new query into newMainQuery 
        // Based on the re-aligned fields in this, re-aligns the
        // corresponding fields in otherQuery as well and modifies 
        // newOtherQuery to contain it 
        // Example:
        //    input:  Proj[A,B,"5"] = Proj[F,"7",G] 
        //            Proj[C,B]     = Proj[H,I]
        //            projectedSlotMap: A -> 0, B -> 1, C -> 2
        //   output:  Proj[A,B,null] = Proj[F,"7",null]
        //            Proj[null,B,C] = Proj[null,I,H] 
        internal void CreateFieldAlignedCellQueries(CellQuery otherQuery, MemberProjectionIndex projectedSlotMap,
                                                    out CellQuery newMainQuery, out CellQuery newOtherQuery) 
        { 

            // mainSlots and otherSlots hold the new slots for two queries 
            int numAlignedSlots = projectedSlotMap.Count;
            ProjectedSlot[] mainSlots = new ProjectedSlot[numAlignedSlots];
            ProjectedSlot[] otherSlots = new ProjectedSlot[numAlignedSlots];
 
            // Go through the slots for this query and find the new slot for them
            for (int i = 0; i < m_projectedSlots.Length; i++) 
            { 

                MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot; 
                Debug.Assert(slot != null, "All slots during cell normalization must field slots");
                // Get the the ith slot's variable and then get the
                // new slot number from the field map
                int newSlotNum = projectedSlotMap.IndexOf(slot.MemberPath); 
                Debug.Assert(newSlotNum >= 0, "Field projected but not in projectedSlotMap");
                mainSlots[newSlotNum] = m_projectedSlots[i]; 
                otherSlots[newSlotNum] = otherQuery.m_projectedSlots[i]; 

                // We ignore constants -- note that this is not the 
                // isHighpriority or discriminator case.  An example of this
                // is when (say) Address does not have zip but USAddress
                // does.  Then the constraint looks like Pi_NULL, A, B(E) =
                // Pi_x, y, z(S) 

                // We don't care about this null in the view generation of 
                // the left side. Note that this could happen in inheritance 
                // or in cases when say the S side has 20 fields but the C
                // side has only 3 - the other 17 are null or default. 

                // NOTE: We allow such constants only on the C side and not
                // ont the S side. Otherwise, we can have a situation Pi_A,
                // B, C(E) = Pi_5, y, z(S) Then someone can set A to 7 and we 
                // will not roundtrip. We check for this in validation
            } 
 
            // Make the new cell queries with the new slots
            newMainQuery = new CellQuery(this, mainSlots); 
            newOtherQuery = new CellQuery(otherQuery, otherSlots);
        }

        // requires: All slots in this are null or non-constants 
        // effects: Returns the non-null slots of this
        internal AttributeSet GetNonNullSlots() 
        { 
            AttributeSet attributes = new AttributeSet(MemberPath.EqualityComparer);
            foreach (ProjectedSlot projectedSlot in m_projectedSlots) 
            {
                // null means 'unused' slot -- we ignore those
                if (projectedSlot != null)
                { 
                    MemberProjectedSlot projectedVar = projectedSlot as MemberProjectedSlot;
                    Debug.Assert(projectedVar != null, "Projected slot must not be a constant"); 
                    attributes.Add(projectedVar.MemberPath); 
                }
            } 
            return attributes;
        }

        // effects: Returns an error record if the keys of the extent/associationSet being mapped  are 
        // present in the projected slots of this query. Returns null
        // otherwise. ownerCell indicates the cell that owns this and 
        // resourceString is a resource used for error messages 
        internal ErrorLog.Record VerifyKeysPresent(Cell ownerCell, Func formatEntitySetMessage,
            Func formatAssociationSetMessage, ViewGenErrorCode errorCode) 
        {
            List prefixes = new List(1);
            // Keep track of the key corresponding to each prefix
            List keys = new List(1); 

            if (Extent is EntitySet) 
            { 
                // For entity set just get the full path of the key properties
                MemberPath prefix = new MemberPath(Extent); 
                prefixes.Add(prefix);
                EntityType entityType = (EntityType)Extent.ElementType;
                List entitySetKeys = ExtentKey.GetKeysForEntityType(prefix, entityType);
                Debug.Assert(entitySetKeys.Count == 1, "Currently, we only support primary keys"); 
                keys.Add(entitySetKeys[0]);
 
            } 
            else
            { 
                AssociationSet relationshipSet = (AssociationSet)Extent;
                // For association set, get the full path of the key
                // properties of each end
 
                foreach (AssociationSetEnd relationEnd in relationshipSet.AssociationSetEnds)
                { 
                    AssociationEndMember assocEndMember = relationEnd.CorrespondingAssociationEndMember; 
                    MemberPath prefix = new MemberPath(relationshipSet, assocEndMember);
                    prefixes.Add(prefix); 
                    List endKeys = ExtentKey.GetKeysForEntityType(prefix,
                                                                             MetadataHelper.GetEntityTypeForEnd(assocEndMember));
                    Debug.Assert(endKeys.Count == 1, "Currently, we only support primary keys");
                    keys.Add(endKeys[0]); 
                }
            } 
 
            for (int i = 0; i < prefixes.Count; i++)
            { 
                MemberPath prefix = prefixes[i];
                // Get all or none key slots that are being projected in this cell query
                List keySlots = MemberProjectedSlot.GetKeySlots(GetMemberProjectedSlots(), prefix);
                if (keySlots == null) 
                {
                    ExtentKey key = keys[i]; 
                    string message; 
                    if (Extent is EntitySet)
                    { 
                        string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, true);
                        message = formatEntitySetMessage(keyPropertiesString, Extent.Name);
                    }
                    else 
                    {
                        string endName = prefix.RootEdmMember.Name; 
                        string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, false); 
                        message = formatAssociationSetMessage(keyPropertiesString, endName, Extent.Name);
                    } 
                    ErrorLog.Record error = new ErrorLog.Record(true, errorCode, message, ownerCell, String.Empty);
                    return error;
                }
            } 
            return null;
        } 
 
        internal IEnumerable GetProjectedMembers()
        { 
            foreach (MemberProjectedSlot slot in this.GetMemberProjectedSlots())
            {
                yield return slot.MemberPath;
            } 
        }
 
        // effects: Returns the fields in this, i.e., not constants or null slots 
        private IEnumerable GetMemberProjectedSlots()
        { 
            foreach (ProjectedSlot slot in m_projectedSlots)
            {
                MemberProjectedSlot memberSlot = slot as MemberProjectedSlot;
                if (memberSlot != null) 
                {
                    yield return memberSlot; 
                } 
            }
        } 

        // effects: Returns the fields that are used in the query (both projected and non-projected)
        // Output list is a copy, i.e., can be modified by the caller
        internal List GetAllQuerySlots() 
        {
            HashSet slots = new HashSet(GetMemberProjectedSlots()); 
            slots.Add(new MemberProjectedSlot(SourceExtentMemberPath)); 
            foreach (var restriction in Conditions)
            { 
                slots.Add(restriction.RestrictedMemberSlot);
            }
            return new List(slots);
        } 

        // effects: returns the index at which this slot appears in the projection 
        // or -1 if it is not projected 
        internal int GetProjectedPosition(MemberProjectedSlot slot)
        { 
            for (int i = 0; i < m_projectedSlots.Length; i++)
            {
                if (MemberProjectedSlot.EqualityComparer.Equals(slot, m_projectedSlots[i]))
                { 
                    return i;
                } 
            } 
            return -1;
        } 

        // effects: returns the List of indexes at which this member appears in the projection
        // or empty list if it is not projected
        internal List GetProjectedPositions(MemberPath member) 
        {
            List pathIndexes = new List(); 
            for (int i = 0; i < m_projectedSlots.Length; i++) 
            {
                MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot; 
                if (slot != null && MemberPath.EqualityComparer.Equals(member, slot.MemberPath))
                {
                    pathIndexes.Add(i);
                } 
            }
            return pathIndexes; 
        } 

        // effects: Determines the slot numbers for members in cellQuery 
        // Returns a set of those paths in the same order as paths. If even
        // one of the path entries is not projected in the cellquery, returns null
        internal List GetProjectedPositions(IEnumerable paths)
        { 
            List pathIndexes = new List();
            foreach (MemberPath member in paths) 
            { 
                // Get the index in checkQuery and add to pathIndexes
                List slotIndexes = GetProjectedPositions(member); 
                Debug.Assert(slotIndexes != null);
                if (slotIndexes.Count == 0)
                { // member is not projected
                    return null; 
                }
                Debug.Assert(slotIndexes.Count == 1, "Expecting the path to be projected only once"); 
                pathIndexes.Add(slotIndexes[0]); 
            }
            return pathIndexes; 
        }

        // effects : Return the slot numbers for members in Cell Query that
        //           represent the association end member passed in. 
        internal List GetAssociationEndSlots(AssociationEndMember endMember)
        { 
            List slotIndexes = new List(); 
            Debug.Assert(this.Extent is AssociationSet);
            for (int i = 0; i < m_projectedSlots.Length; i++) 
            {
                MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot;
                if (slot != null && slot.MemberPath.RootEdmMember.Equals(endMember))
                { 
                    slotIndexes.Add(i);
                } 
            } 
            return slotIndexes;
        } 

        // effects: Determines the slot numbers for members in cellQuery
        // Returns a set of those paths in the same order as paths. If even
        // one of the path entries is not projected in the cellquery, returns null 
        // If a path is projected more than once, than we choose the one from the
        // slotsToSearchFrom domain. 
        internal List GetProjectedPositions(IEnumerable paths, List slotsToSearchFrom) 
        {
            List pathIndexes = new List(); 
            foreach (MemberPath member in paths)
            {
                // Get the index in checkQuery and add to pathIndexes
                List slotIndexes = GetProjectedPositions(member); 
                Debug.Assert(slotIndexes != null);
                if (slotIndexes.Count == 0) 
                { // member is not projected 
                    return null;
                } 
                int slotIndex = -1;
                if (slotIndexes.Count > 1)
                {
                    for (int i = 0; i < slotIndexes.Count; i++) 
                    {
                        if (slotsToSearchFrom.Contains(slotIndexes[i])) 
                        { 
                            Debug.Assert(slotIndex == -1, "Should be projected only once");
                            slotIndex = slotIndexes[i]; 
                        }
                    }
                    if (slotIndex == -1)
                    { 
                        return null;
                    } 
                } 
                else
                { 
                    slotIndex = slotIndexes[0];
                }
                pathIndexes.Add(slotIndex);
            } 
            return pathIndexes;
        } 
 

        // requires: The CellConstantDomains in the OneOfConsts of the where 
        // clause are partially done
        // effects: Given the domains of different variables in domainMap,
        // fixes the whereClause of this such that all the
        // CellConstantDomains in OneOfConsts are fully done 
        internal void UpdateWhereClause(MemberDomainMap domainMap)
        { 
            List atoms = new List(); 
            foreach (BoolExpression atom in WhereClause.Atoms)
            { 
                BoolLiteral literal = atom.AsLiteral;
                MemberRestriction restriction = literal as MemberRestriction;
                Debug.Assert(restriction != null, "All bool literals must be OneOfConst at this point");
                // The oneOfConst needs to be fixed with the new possible 
                // values from the domainMap
                IEnumerable possibleValues = domainMap.GetDomain(restriction.RestrictedMemberSlot.MemberPath); 
                MemberRestriction newOneOf = MemberRestriction.CreateFullOneOfConst(restriction, possibleValues); 

 
                // Prevent optimization of single constraint e.g: "300 in (300)"
                // But we want to optimize type constants e.g: "category in (Category)"
                // To prevent optimization of bool expressions we add a Sentinel OneOF
 
                ScalarRestriction scalarConst = restriction as ScalarRestriction;
                bool addSentinel = 
                    scalarConst != null && 
                    !scalarConst.Domain.Contains(Constant.Null) &&
                    !scalarConst.Domain.Contains(Constant.NotNull) && 
                    !scalarConst.Domain.Contains(Constant.Undefined);

                if (addSentinel)
                { 
                    domainMap.AddSentinel(newOneOf.RestrictedMemberSlot.MemberPath);
                } 
 
                atoms.Add(BoolExpression.CreateLiteral(newOneOf, domainMap));
 
                if (addSentinel)
                {
                    domainMap.RemoveSentinel(newOneOf.RestrictedMemberSlot.MemberPath);
                } 

            } 
            // We create a new whereClause that has the memberDomainMap set 
            if (atoms.Count > 0)
            { 
                m_whereClause = BoolExpression.CreateAnd(atoms.ToArray());
            }
        }
        #endregion 

        #region BooleanExprs related Methods 
        // effects: Returns a boolean expression corresponding to the 
        // "varNum" boolean in this.
        internal BoolExpression GetBoolVar(int varNum) 
        {
            return m_boolExprs[varNum];
        }
 
        // effects: Initalizes the booleans of this cell query to be
        // true. Creates numBoolVars booleans and sets the cellNum boolean to true 
        internal void InitializeBoolExpressions(int numBoolVars, int cellNum) 
        {
            //Debug.Assert(m_boolExprs.Count == 0, "Overwriting existing booleans"); 
            m_boolExprs = new List(numBoolVars);
            for (int i = 0; i < numBoolVars; i++)
            {
                m_boolExprs.Add(null); 
            }
            Debug.Assert(cellNum < numBoolVars, "Trying to set boolean with too high an index"); 
            m_boolExprs[cellNum] = BoolExpression.True; 
        }
 
        #endregion
        #region WhereClause related methods
        // requires: The current whereClause corresponds to "True", "OneOfConst" or "
        // "OneOfConst AND ... AND OneOfConst" 
        // effects: Yields all the conjuncts (OneOfConsts) in this (i.e., if the whereClause is
        // just True, yields nothing 
        internal IEnumerable GetConjunctsFromWhereClause() 
        {
            return GetConjunctsFromWhereClause(m_whereClause); 
        }

        internal IEnumerable GetConjunctsFromOriginalWhereClause()
        { 
            return GetConjunctsFromWhereClause(m_originalWhereClause);
        } 
 

        private IEnumerable GetConjunctsFromWhereClause(BoolExpression whereClause) 
        {
            foreach (BoolExpression boolExpr in whereClause.Atoms)
            {
                if (boolExpr.IsTrue) 
                {
                    continue; 
                } 
                MemberRestriction result = boolExpr.AsLiteral as MemberRestriction;
                Debug.Assert(result != null, "Atom must be restriction"); 
                yield return result;
            }
        }
 
        // requires: whereClause is of the form specified in GetConjunctsFromWhereClause
        // effects: Converts the whereclause to a user-readable string 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 
        internal void WhereClauseToUserString(StringBuilder builder, MetadataWorkspace workspace)
        { 
            bool isFirst = true;
            foreach (MemberRestriction restriction in GetConjunctsFromWhereClause())
            {
                if (isFirst == false) 
                {
                    builder.Append(System.Data.Entity.Strings.ViewGen_AND); 
                } 
                restriction.ToUserString(false, builder, workspace);
            } 
        }
        #endregion

        #region Full CellQuery methods 
        // effects: Determines all the identifiers used in this and adds them to identifiers
        internal void GetIdentifiers(CqlIdentifiers identifiers) 
        { 
            foreach (ProjectedSlot projectedSlot in m_projectedSlots)
            { 
                MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot;
                if (slot != null)
                {
                    slot.MemberPath.GetIdentifiers(identifiers); 
                }
            } 
            m_extentMemberPath.GetIdentifiers(identifiers); 
        }
 
        internal void CreateBasicCellRelation(ViewCellRelation viewCellRelation)
        {
            List slots = GetAllQuerySlots();
            // Create a base cell relation that has all the scalar slots of this 
            m_basicCellRelation = new BasicCellRelation(this, viewCellRelation, slots);
        } 
 

 
        #endregion

        #region String Methods
        // effects: Modifies stringBuilder to contain a string representation 
        // of the cell query in terms of the original cells that are being used
        internal override void ToCompactString(StringBuilder stringBuilder) 
        { 
            // This could be a simplified view where a number of cells
            // got merged or it could be one of the original booleans. So 
            // determine their numbers using the booleans in m_cellWrapper
            List boolExprs = m_boolExprs;
            int i = 0;
            bool first = true; 
            foreach (BoolExpression boolExpr in boolExprs)
            { 
                if (boolExpr != null) 
                {
                    if (false == first) 
                    {
                        stringBuilder.Append(",");
                    }
                    else 
                    {
                        stringBuilder.Append("["); 
                    } 
                    StringUtil.FormatStringBuilder(stringBuilder, "C{0}", i);
                    first = false; 
                }
                i++;
            }
            if (true == first) 
            {
                // No booleans, i.e., no compact representation. Use full string to avoid empty output 
                ToFullString(stringBuilder); 
            }
            else 
            {
                stringBuilder.Append("]");
            }
        } 

        internal override void ToFullString(StringBuilder builder) 
        { 
            builder.Append("SELECT ");
 
            if (m_selectDistinct == SelectDistinct.Yes)
            {
                builder.Append("DISTINCT ");
            } 

            StringUtil.ToSeparatedString(builder, m_projectedSlots, ", ", "_"); 
 
            if (m_boolExprs.Count > 0)
            { 
                builder.Append(", Bool[");
                StringUtil.ToSeparatedString(builder, m_boolExprs, ", ", "_");
                builder.Append("]");
            } 

            builder.Append(" FROM "); 
            m_extentMemberPath.ToFullString(builder); 

            if (false == m_whereClause.IsTrue) 
            {
                builder.Append(" WHERE ");
                m_whereClause.ToFullString(builder);
            } 
        }
 
        public override string ToString() 
        {
            return ToFullString(); 
        }

        // eSQL representation of cell query
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 
        internal string ToESqlString()
        { 
            StringBuilder builder = new StringBuilder(); 
            builder.Append("\n\tSELECT ");
 
            if (m_selectDistinct == SelectDistinct.Yes)
            {
                builder.Append("DISTINCT ");
            } 

            foreach (ProjectedSlot ps in m_projectedSlots) 
            { 
                MemberProjectedSlot jtn = ps as MemberProjectedSlot;
                StructuralType st = jtn.MemberPath.LeafEdmMember.DeclaringType; 
                StringBuilder sb = new StringBuilder();
                jtn.MemberPath.AsCql(sb, "e");
                builder.AppendFormat("{0}, ", sb.ToString());
            } 
            //remove the extra-comma after the last slot
            builder.Remove(builder.Length - 2, 2); 
 
            builder.Append("\n\tFROM ");
            EntitySetBase extent = m_extentMemberPath.Extent; 
            CqlWriter.AppendEscapedQualifiedName(builder, extent.EntityContainer.Name, extent.Name);
            builder.Append(" AS e");

            if (m_whereClause.IsTrue == false) 
            {
                builder.Append("\n\tWHERE "); 
 
                StringBuilder qbuilder = new StringBuilder();
                m_whereClause.AsCql(qbuilder, "e"); 

                builder.Append(qbuilder.ToString());
            }
            builder.Append("\n    "); 

            return builder.ToString(); 
        } 

        #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