ViewgenContext.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 / ViewgenContext.cs / 1305376 / ViewgenContext.cs

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

using System.Data.Common.Utils; 
using System.Data.Common.Utils.Boolean;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Collections.Generic;
using System.Text; 
using System.Data.Mapping.ViewGeneration.Validation;
using System.Data.Mapping.ViewGeneration.QueryRewriting; 
using System.Diagnostics; 
using System.Collections.ObjectModel;
using System.Data.Mapping.ViewGeneration.Utils; 
using System.Data.Metadata.Edm;
using System.Linq;
using System.Data.Entity;
 
namespace System.Data.Mapping.ViewGeneration
{ 
    internal class ViewgenContext : InternalBase 
    {
 
        #region Fields

        private ConfigViewGenerator m_config;
        private ViewTarget m_viewTarget; 

        // Extent for which the view is being generated 
        private EntitySetBase m_extent; 

        // Different maps for members 
        private MemberMaps m_memberMaps;
        private EdmItemCollection m_edmItemCollection;
        private StorageEntityContainerMapping m_entityContainerMapping;
 
        // The normalized cells that are created
        private List m_cellWrappers; 
 
        // Implicit constraints between members in queries based on schema. E.g., p.Addr IS NOT NULL <=> p IS OF Customer
        private FragmentQueryProcessor m_leftFragmentQP; 

        // In addition to constraints for each right extent contains constraints due to associations
        private FragmentQueryProcessor m_rightFragmentQP;
 
        private CqlIdentifiers m_identifiers;
 
        // Maps (left) queries to their rewritings in terms of views 
        private Dictionary> m_rewritingCache;
 

        #endregion

        #region Constructors 
        internal ViewgenContext(ViewTarget viewTarget, EntitySetBase extent, IEnumerable extentCells,
                                CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap, 
                                MemberDomainMap updateDomainMap, StorageEntityContainerMapping entityContainerMapping) 
        {
            foreach (Cell cell in extentCells) 
            {
                Debug.Assert(extent.Equals(cell.GetLeftQuery(viewTarget).Extent));
                Debug.Assert(cell.CQuery.NumProjectedSlots == cell.SQuery.NumProjectedSlots);
            } 

            m_extent = extent; 
            m_viewTarget = viewTarget; 
            m_config = config;
            m_edmItemCollection = entityContainerMapping.StorageMappingItemCollection.EdmItemCollection; 
            m_entityContainerMapping = entityContainerMapping;
            m_identifiers = identifiers;

            // create a copy of updateDomainMap so generation of query views later on is not affected 
            // it is modified in QueryRewriter.AdjustMemberDomainsForUpdateViews
            updateDomainMap = updateDomainMap.MakeCopy(); 
 
            // Create a signature generator that handles all the
            // multiconstant work and generating the signatures 
            MemberDomainMap domainMap = viewTarget == ViewTarget.QueryView ? queryDomainMap : updateDomainMap;

            m_memberMaps = new MemberMaps(viewTarget, MemberProjectionIndex.Create(extent, m_edmItemCollection), queryDomainMap, updateDomainMap);
 
            // Create left fragment KB: includes constraints for the extent to be constructed
            FragmentQueryKB leftKB = new FragmentQueryKB(); 
            leftKB.CreateVariableConstraints(extent, domainMap, m_edmItemCollection); 
            m_leftFragmentQP = new FragmentQueryProcessor(leftKB);
            m_rewritingCache = new Dictionary>( 
                FragmentQuery.GetEqualityComparer(m_leftFragmentQP));

            // Now using the signatures, create new cells such that
            // "extent's" query (C or S) is described in terms of multiconstants 
            if (!CreateLeftCellWrappers(extentCells, viewTarget))
            { 
                return; 
            }
 
            // Create right fragment KB: includes constraints for all extents and association roles of right queries
            FragmentQueryKB rightKB = new FragmentQueryKB();
            MemberDomainMap rightDomainMap = viewTarget == ViewTarget.QueryView ? updateDomainMap : queryDomainMap;
            foreach (LeftCellWrapper leftCellWrapper in m_cellWrappers) 
            {
                EntitySetBase rightExtent = leftCellWrapper.RightExtent; 
                rightKB.CreateVariableConstraints(rightExtent, rightDomainMap, m_edmItemCollection); 
                rightKB.CreateAssociationConstraints(rightExtent, rightDomainMap, m_edmItemCollection);
            } 

            if (m_viewTarget == ViewTarget.UpdateView)
            {
                CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper(rightKB, rightDomainMap); 
            }
 
            m_rightFragmentQP = new FragmentQueryProcessor(rightKB); 

            // Check for concurrency control tokens 
            if (m_viewTarget == ViewTarget.QueryView)
            {
                CheckConcurrencyControlTokens();
            } 
            // For backward compatibility -
            // order wrappers by increasing domain size, decreasing number of attributes 
            m_cellWrappers.Sort(LeftCellWrapper.Comparer); 
        }
 
        /// 
        /// Find the Foreign Key Associations that relate EntitySets used in these left cell wrappers and
        /// add any equivalence facts between sets implied by 1:1 associations.
        /// We can collect other implication facts but we don't have a scenario that needs them( yet ). 
        /// 
        ///  
        ///  
        private void CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper(FragmentQueryKB rightKB, MemberDomainMap rightDomainMap)
        { 
            //First find the entity types of the sets in these cell wrappers.
            var entityTypes = m_cellWrappers.Select(it => it.RightExtent).OfType().Select(it => it.ElementType);
            //Get all the foreign key association sets in these entity sets
            var allForeignKeyAssociationSets = this.m_entityContainerMapping.EdmEntityContainer.BaseEntitySets.OfType().Where(it => it.ElementType.IsForeignKey); 
            //Find all the foreign key associations that have corresponding sets
            var oneToOneForeignKeyAssociationsForThisWrapper = allForeignKeyAssociationSets.Select(it => it.ElementType); 
            //Find all the 1:1 associations from the above list 
            oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where(it => (it.AssociationEndMembers.All(endMember => endMember.RelationshipMultiplicity == RelationshipMultiplicity.One)));
            //Filter the 1:1 foreign key associations to the ones relating the sets used in these cell wrappers. 
            oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where(it => (it.AssociationEndMembers.All(endMember => entityTypes.Contains(endMember.GetEntityType()))));

            //filter foreign key association sets to the sets that are 1:1 and affecting this wrapper.
            var oneToOneForeignKeyAssociationSetsForThisWrapper = allForeignKeyAssociationSets.Where(it => oneToOneForeignKeyAssociationsForThisWrapper.Contains(it.ElementType)); 

            //Collect the facts for the foreign key association sets that are 1:1 and affecting this wrapper 
            foreach (var assocSet in oneToOneForeignKeyAssociationSetsForThisWrapper) 
            {
                rightKB.CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(assocSet, rightDomainMap, m_edmItemCollection); 
            }
        }

        #endregion 

 
        #region Properties 
        internal ViewTarget ViewTarget
        { 
            get
            {
                return m_viewTarget;
            } 
        }
 
        internal MemberMaps MemberMaps 
        {
            get 
            {
                return m_memberMaps;
            }
        } 

        // effects: Returns the extent for which the cells have been normalized 
        internal EntitySetBase Extent 
        {
            get { return m_extent; } 
        }

        internal ConfigViewGenerator Config
        { 
            get { return m_config; }
        } 
 
        internal CqlIdentifiers CqlIdentifiers
        { 
            get { return m_identifiers; }
        }

        internal EdmItemCollection EdmItemCollection 
        {
            get { return m_edmItemCollection; } 
        } 

        internal FragmentQueryProcessor LeftFragmentQP 
        {
            get { return m_leftFragmentQP; }
        }
 
        internal FragmentQueryProcessor RightFragmentQP
        { 
            get { return m_rightFragmentQP; } 
        }
 
        // effects: Returns all wrappers that were originally relevant for
        // this extent
        internal List AllWrappersForExtent
        { 
            get
            { 
                return m_cellWrappers; 
            }
        } 

        internal StorageEntityContainerMapping EntityContainerMapping
        {
            get { return m_entityContainerMapping; } 
        }
        #endregion 
 
        #region InternalMethods
 
        // effects: Returns the cached rewriting of (left) queries in terms of views, if any
        internal bool TryGetCachedRewriting(FragmentQuery query, out Tile rewriting)
        {
            return m_rewritingCache.TryGetValue(query, out rewriting); 
        }
 
        // effects: Records the cached rewriting of (left) queries in terms of views 
        internal void SetCachedRewriting(FragmentQuery query, Tile rewriting)
        { 
            m_rewritingCache[query] = rewriting;
        }

        #endregion 

        #region Private Methods 
 

        ///  
        /// Checks:
        ///  1) Concurrency token is not defined in this Extent's ElementTypes' derived types
        ///  2) Members with concurrency token should not have conditions specified
        ///  
        private void CheckConcurrencyControlTokens()
        { 
            Debug.Assert(m_viewTarget == ViewTarget.QueryView); 
            // Get the token fields for this extent
 
            EntityTypeBase extentType = m_extent.ElementType;
            Set tokenMembers = MetadataHelper.GetConcurrencyMembersForTypeHierarchy(extentType, m_edmItemCollection);
            Set tokenPaths = new Set(MemberPath.EqualityComparer);
            foreach (EdmMember tokenMember in tokenMembers) 
            {
                if (!tokenMember.DeclaringType.Equals(extentType)) 
                { 
                    string message = System.Data.Entity.Strings.ViewGen_Concurrency_Derived_Class_2(tokenMember.Name, tokenMember.DeclaringType.Name, m_extent);
                    ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.ConcurrencyDerivedClass, message, m_cellWrappers, String.Empty); 
                    ExceptionHelpers.ThrowMappingException(record, m_config);
                }
                tokenPaths.Add(new MemberPath(m_extent, tokenMember));
            } 

            if (tokenMembers.Count > 0) 
            { 
                foreach (LeftCellWrapper wrapper in m_cellWrappers)
                { 
                    Set conditionMembers = new Set(
                                                            wrapper.OnlyInputCell.CQuery.WhereClause.MemberRestrictions.Select(oneOf => oneOf.RestrictedMemberSlot.MemberPath),
                                                            MemberPath.EqualityComparer);
                    conditionMembers.Intersect(tokenPaths); 
                    if (conditionMembers.Count > 0)
                    { 
                        // There is a condition on concurrency tokens. Throw an exception. 
                        StringBuilder builder = new StringBuilder();
                        builder.AppendLine(Strings.ViewGen_Concurrency_Invalid_Condition_1(MemberPath.PropertiesToUserString(conditionMembers, false), m_extent.Name)); 
                        ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.ConcurrencyTokenHasCondition, builder.ToString(), new LeftCellWrapper[] { wrapper }, String.Empty);
                        ExceptionHelpers.ThrowMappingException(record, m_config);
                    }
                } 
            }
        } 
 

        // effects: Given the cells for the extent (extentCells) along with 
        // the signatures (multiconstants + needed attributes) for this extent, generates
        // the left cell wrappers for it extent (viewTarget indicates whether
        // the view is for querying or update purposes
        // Modifies m_cellWrappers to contain this list 
        private bool CreateLeftCellWrappers(IEnumerable extentCells, ViewTarget viewTarget)
        { 
 
            List extentCellsList = new List(extentCells);
            List alignedCells = AlignFields(extentCellsList, m_memberMaps.ProjectedSlotMap, viewTarget); 
            Debug.Assert(alignedCells.Count == extentCellsList.Count, "Cell counts disagree");

            // Go through all the cells and create cell wrappers that can be used for generating the view
            m_cellWrappers = new List(); 

            for (int i = 0; i < alignedCells.Count; i++) 
            { 
                Cell alignedCell = alignedCells[i];
                CellQuery left = alignedCell.GetLeftQuery(viewTarget); 
                CellQuery right = alignedCell.GetRightQuery(viewTarget);

                // Obtain the non-null projected slots into attributes
                Set attributes = left.GetNonNullSlots(); 

                BoolExpression fromVariable = BoolExpression.CreateLiteral(new CellIdBoolean(m_identifiers, extentCellsList[i].CellNumber), m_memberMaps.LeftDomainMap); 
                FragmentQuery leftFragmentQuery = FragmentQuery.Create(fromVariable, left); 
                FragmentQuery rightFragmentQuery = FragmentQuery.Create(fromVariable, right);
                if (viewTarget == ViewTarget.UpdateView) 
                {
                    leftFragmentQuery = m_leftFragmentQP.CreateDerivedViewBySelectingConstantAttributes(leftFragmentQuery) ?? leftFragmentQuery;
                }
 
                LeftCellWrapper leftWrapper = new LeftCellWrapper(m_viewTarget, attributes, leftFragmentQuery, left, right, m_memberMaps,
                                                                  extentCellsList[i]); 
                m_cellWrappers.Add(leftWrapper); 
            }
            return true; 
        }

        // effects: Align the fields of each cell in mapping using projectedSlotMap that has a mapping
        // for each member of this extent to the slot number of that member in the projected slots 
        // example:
        //    input:  Proj[A,B,"5"] = Proj[F,"7",G] 
        //            Proj[C,B]     = Proj[H,I] 
        //   output:  m_projectedSlotMap: A -> 0, B -> 1, C -> 2
        //            Proj[A,B,null] = Proj[F,"7",null] 
        //            Proj[null,B,C] = Proj[null,I,H]
        private static List AlignFields(IEnumerable cells, MemberProjectionIndex projectedSlotMap,
                                              ViewTarget viewTarget)
        { 

            List outputCells = new List(); 
 
            // Determine the aligned field for each cell
            // The new cells have ProjectedSlotMap.Count number of fields 
            foreach (Cell cell in cells)
            {

                // If isQueryView is true, we need to consider the C side of 
                // the cells; otherwise, we look at the S side. Note that we
                // CANNOT use cell.LeftQuery since that is determined by 
                // cell's isQueryView 

                // The query for which we are constructing the extent 
                CellQuery mainQuery = cell.GetLeftQuery(viewTarget);
                CellQuery otherQuery = cell.GetRightQuery(viewTarget);

                CellQuery newMainQuery; 
                CellQuery newOtherQuery;
                // Create both queries where the projected slot map is used 
                // to determine the order of the fields of the mainquery (of 
                // course, the otherQuery's fields are aligned automatically)
                mainQuery.CreateFieldAlignedCellQueries(otherQuery, projectedSlotMap, 
                                                        out newMainQuery, out newOtherQuery);

                Cell outputCell = viewTarget == ViewTarget.QueryView ?
                    Cell.CreateCS(newMainQuery, newOtherQuery, cell.CellLabel, cell.CellNumber) : 
                    Cell.CreateCS(newOtherQuery, newMainQuery, cell.CellLabel, cell.CellNumber);
                outputCells.Add(outputCell); 
            } 
            return outputCells;
        } 

        #endregion

        #region String Methods 
        internal override void ToCompactString(StringBuilder builder)
        { 
            LeftCellWrapper.WrappersToStringBuilder(builder, m_cellWrappers, "Left Celll Wrappers"); 
        }
 
        #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