ViewGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / ViewGenerator.cs / 4 / ViewGenerator.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.Data.Mapping.ViewGeneration.Validation;
using System.Data.Mapping.ViewGeneration.QueryRewriting; 
using System.Collections.Generic;
using System.Text; 
using System.Diagnostics; 
using System.Data.Mapping.ViewGeneration.Utils;
using System.Data.Metadata.Edm; 
using System.Linq;

namespace System.Data.Mapping.ViewGeneration {
 
    using ViewSet            = KeyToListMap;
    using CellGroup          = Set; 
    using WrapperBoolExpr    = BoolExpr; 
    using WrapperTrueExpr    = TrueExpr;
    using WrapperFalseExpr   = FalseExpr; 
    using WrapperNotExpr     = NotExpr;
    using WrapperOrExpr      = OrExpr;

    // This class is responsible for generating query or update mapping 
    // views from the initial cells.
    internal class ViewGenerator : InternalBase { 
 
        #region Constructor
        // effects: Creates a ViewGenerator object that is capable of 
        // producing query or update mapping views given the relevant schema
        // given the "cells"
        private ViewGenerator(CellGroup cellGroup, ConfigViewGenerator config,
                              List foreignKeyConstraints, 
                              StorageEntityContainerMapping entityContainerMapping,
                              MetadataWorkspace workSpace ) { 
 
            m_cellGroup = cellGroup;
            m_config = config; 
            m_workSpace = workSpace;
            m_queryRewriterMap = new Dictionary();
            m_foreignKeyConstraints = foreignKeyConstraints;
            m_entityContainerMapping = entityContainerMapping; 

            Dictionary> inheritanceGraph = MetadataHelper.BuildUndirectedGraphOfTypes(m_workSpace); 
 
            // We fix all the cells at this point
            m_queryDomainMap = new MemberDomainMap(ViewTarget.QueryView, cellGroup, m_workSpace, m_config, inheritanceGraph); 
            m_updateDomainMap = new MemberDomainMap(ViewTarget.UpdateView, cellGroup, m_workSpace, m_config, inheritanceGraph);

            // We now go and fix the queryDomain map so that it has all the
            // values from the S-side as well -- this is needed for domain 
            // constraint propagation, i.e., values from the S-side get
            // propagated to te oneOfConst on the C-side. So we better get 
            // the "possiblveValues" stuff to contain those constants as well 
            m_queryDomainMap.FixQueryDomainMap(cellGroup, m_updateDomainMap);
 
            FixCellConstantDomains(ViewTarget.QueryView, cellGroup, m_queryDomainMap, m_config);
            FixCellConstantDomains(ViewTarget.UpdateView, cellGroup, m_updateDomainMap, m_config);

            // We need to simplify cell queries, yet we don't want the conditions to disappear 
            // So, add an extra value to the domain, temporarily
            MemberDomainMap queryOpenDomain = m_queryDomainMap.GetOpenDomain(); 
            MemberDomainMap updateOpenDomain = m_updateDomainMap.GetOpenDomain(); 

            // Make sure the WHERE clauses of the cells reflect the changes 
            foreach (Cell cell in cellGroup)
            {
                cell.CQuery.WhereClause.FixDomainMap(queryOpenDomain);
                cell.SQuery.WhereClause.FixDomainMap(updateOpenDomain); 
                cell.CQuery.WhereClause.ExpensiveSimplify();
                cell.SQuery.WhereClause.ExpensiveSimplify(); 
                cell.CQuery.WhereClause.FixDomainMap(m_queryDomainMap); 
                cell.SQuery.WhereClause.FixDomainMap(m_updateDomainMap);
            } 
        }

        // effects: Given the extent cells and a map for the domains of all
        // variables in it, fixes the cell constant domains of the where 
        // clauses in the left queries of cells (left is defined using viewTarget)
        private static void FixCellConstantDomains(ViewTarget viewTarget, IEnumerable extentCells, 
                                                   MemberDomainMap domainMap, ConfigViewGenerator config) { 
            foreach (Cell cell in extentCells) {
                CellQuery cellQuery = cell.GetLeftQuery(viewTarget); 
                cellQuery.FixCellConstantDomains(domainMap, viewTarget);
            }

            // Fix domains of enumerated and boolean types -- i.e., whose 
            // domains are enumerable
            domainMap.FixEnumerableDomains(config); 
        } 
        #endregion
 
        #region Fields
        // internal static ConfigViewGenerator Config = null;
        private CellGroup m_cellGroup; // The initial cells from which we produce views
        private ConfigViewGenerator m_config; // Configuration variables 
        private MemberDomainMap m_queryDomainMap;
        private MemberDomainMap m_updateDomainMap; 
        private Dictionary m_queryRewriterMap; 
        private List m_foreignKeyConstraints;
        private MetadataWorkspace m_workSpace; 

        private StorageEntityContainerMapping m_entityContainerMapping;

        #endregion 

        #region External Methods 
        // effects: Given a mappingschema object, generates the query and 
        // update mapping views for OFTYPE(Extent, Type) combinations in this schema
        // container. Returns a list of generated query and update views. 
        internal static ViewGenResults GenerateViewsForSchema(StorageEntityContainerMapping containerMapping,
                                                              MetadataWorkspace workSpace,
                                                              ConfigViewGenerator config) {
            EntityUtil.CheckArgumentNull(containerMapping, "containerMapping"); 
            EntityUtil.CheckArgumentNull(config, "config");
 
            CellCreator cellCreator = new CellCreator(containerMapping, workSpace); 
            List cells = cellCreator.GenerateCells(config);
            CqlIdentifiers identifiers = cellCreator.Identifiers; 

            return GenerateViewsForSchemaCells(cells, workSpace, config, identifiers, containerMapping);
        }
 
        // effects: Given a list of cells in the schema, generates the query and
        // update mapping views for OFTYPE(Extent, Type) combinations in this schema 
        // container. Returns a list of generated query and update views. 
        // If it is false and some columns in a table are unmapped, an
        // exception is raised 
        internal static ViewGenResults GenerateViewsForSchemaCells(List cells, MetadataWorkspace workSpace,
                                                                   ConfigViewGenerator config,
                                                                   CqlIdentifiers identifiers,
                                                                   StorageEntityContainerMapping containerMapping) { 

            EntityUtil.CheckArgumentNull(cells, "cells"); 
            EntityUtil.CheckArgumentNull(config, "config"); 
            Debug.Assert(cells.Count > 0, "There must be at least one cell in the container mapping");
 
            // CHANGE_[....]_DESIGN: Derive S keys and store them away --
            // validation. From this point on, only use that key information

            // Go through each table and determine their foreign key constraints 
            EntityContainer container = containerMapping.StorageEntityContainer;
 
            Debug.Assert(container != null); 

            ViewGenResults viewGenResults = new ViewGenResults(); 
            ErrorLog tmpLog = EnsureAllCSpaceContainerSetsAreMapped(cells, config, containerMapping);
            if (tmpLog.Count > 0) {
                viewGenResults.AddErrors(tmpLog);
                Helpers.StringTraceLine(viewGenResults.ErrorsToString()); 
                return viewGenResults;
            } 
 
            List foreignKeyConstraints = ForeignConstraint.GetForeignConstraints(container, workSpace);
 
            CellPartitioner partitioner = new CellPartitioner(cells, foreignKeyConstraints);
            List cellGroups = partitioner.GroupRelatedCells();
            foreach (CellGroup cellGroup in cellGroups) {
                ViewGenerator viewGenerator = null; 
                ErrorLog groupErrorLog = new ErrorLog();
                try { 
                    viewGenerator = new ViewGenerator(cellGroup, config, foreignKeyConstraints, containerMapping, workSpace); 
                } catch (InternalMappingException exception) {
                    // All exceptions have mapping errors in them 
                    Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                    groupErrorLog = exception.ErrorLog;
                }
 
                if (groupErrorLog.Count == 0) {
                    Debug.Assert(viewGenerator != null); 
                    groupErrorLog = viewGenerator.GenerateAllViews(viewGenResults.Views, identifiers); 
                }
 
                if (groupErrorLog.Count != 0) {
                    viewGenResults.AddErrors(groupErrorLog);
                }
            } 
            // We used to print the errors here. Now we trace them as they are being thrown
            //if (viewGenResults.HasErrors && config.IsViewTracing) { 
            //    Helpers.StringTraceLine(viewGenResults.ErrorsToString()); 
            //}
            return viewGenResults; 
        }


        internal static ViewGenResults GenerateQueryViewOfType(StorageEntityContainerMapping containerMapping, 
                                                              MetadataWorkspace workSpace,
                                                              ConfigViewGenerator config, 
                                                              EntitySetBase entity, 
                                                              EntityTypeBase type,
                                                              bool includeSubtypes, 
                                                              out bool success)
        {
            EntityUtil.CheckArgumentNull(containerMapping, "containerMapping");
            EntityUtil.CheckArgumentNull(config, "config"); 
            EntityUtil.CheckArgumentNull(entity, "entity");
            EntityUtil.CheckArgumentNull(type, "type"); 
            Debug.Assert(!type.Abstract, "Can not generate OfType/OfTypeOnly query view for and abstract type"); 

            if (config.IsNormalTracing) 
            {
                Helpers.StringTraceLine("");
                Helpers.StringTraceLine("<<<<<<<< Generating Query View for Entity [" + entity.Name + "] OfType" + (includeSubtypes ? "" : "Only") + "(" + type.Name + ") >>>>>>>");
            } 

            if (containerMapping.GetEntitySetMapping(entity.Name).QueryView != null) 
            { 
                //Type-specific QV does not exist in the cache, but
                // there is a EntitySet QV. So we can't generate the view (no mapping exists for this EntitySet) 
                // and we rely on Query to call us again to get the EntitySet View.
                success = false;
                return null;
            } 

            //Compute Cell Groups or get it from Memoizer 
            InputForComputingCellGroups args = new InputForComputingCellGroups(containerMapping, config); 

            OutputFromComputeCellGroups result = containerMapping.GetCellgroups(args); 
            success = result.Success;

            if (!success)
            { 
                return null;
            } 
 
            List foreignKeyConstraints = result.ForeignKeyConstraints;
            // Get a Clone of cell groups from cache since cells are modified during viewgen, and we dont want the cached copy to change 
            List cellGroups = cellGroups = result.CellGroups.Select(setOfcells => new CellGroup(setOfcells.Select(cell => new Cell(cell)))).ToList();
            List cells = result.Cells;
            CqlIdentifiers identifiers = result.Identifiers;
 

            ViewGenResults viewGenResults = new ViewGenResults(); 
            ErrorLog tmpLog = EnsureAllCSpaceContainerSetsAreMapped(cells, config, containerMapping); 
            if (tmpLog.Count > 0)
            { 
                viewGenResults.AddErrors(tmpLog);
                Helpers.StringTraceLine(viewGenResults.ErrorsToString());
                success = true; //atleast we tried successfully
                return viewGenResults; 
            }
 
            foreach (CellGroup cellGroup in cellGroups) 
            {
                if (!DoesGroupContainExtent(cellGroup, entity)) 
                {
                    continue;
                }
 
                ViewGenerator viewGenerator = null;
                ErrorLog groupErrorLog = new ErrorLog(); 
                try 
                {
                    viewGenerator = new ViewGenerator(cellGroup, config, foreignKeyConstraints, containerMapping, workSpace); 
                }
                catch (InternalMappingException exception)
                {
                    // All exceptions have mapping errors in them 
                    Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                    groupErrorLog = exception.ErrorLog; 
                } 

                if (groupErrorLog.Count > 0) 
                {
                    break;
                }
                Debug.Assert(viewGenerator != null); //make sure there is no exception thrown that does not add error to log 

                ViewGenerationMode mode = includeSubtypes?ViewGenerationMode.OfTypeViews: ViewGenerationMode.OfTypeOnlyViews; 
 
                groupErrorLog = viewGenerator.GenerateQueryViewForSingleExtent(viewGenResults.Views, identifiers, entity, type, mode);
 
                if (groupErrorLog.Count != 0)
                {
                    viewGenResults.AddErrors(groupErrorLog);
                } 
            }
 
            success = true; 
            return viewGenResults;
        } 

        #endregion

        #region Private Methods 

        private static bool DoesGroupContainExtent(CellGroup group, EntitySetBase entity) 
        { 
            foreach(Cell cell in group)
            { 
                if (cell.GetLeftQuery(ViewTarget.QueryView).Extent.Equals(entity))
                {
                    return true;
                } 
            }
 
            return false; 
        }
 
        private ErrorLog GenerateQueryViewForSingleExtent(ViewSet views, CqlIdentifiers identifiers, EntitySetBase entity, EntityTypeBase type, ViewGenerationMode mode)
        {
            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews);
 
            if (m_config.IsNormalTracing)
            { 
                StringBuilder builder = new StringBuilder(); 
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString()); 
            }

            // Check if the cellgroup is consistent and all known S constraints are
            // satisified by the known C constraints 
            Validator validator = new Validator(m_cellGroup, m_config);
            ErrorLog errorLog = validator.Validate(m_workSpace); 
            if (errorLog.Count > 0) 
            {
                errorLog.PrintTrace(); 
                return errorLog;
            }

            // Make sure that the foreign key constraints are not violated 
            if (m_config.IsValidationEnabled)
            { 
                CheckForeignKeyConstraints(errorLog, m_workSpace); 
            }
 
            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views 
            }
 
            // For the S-side, we add NOT ... for each scalar constant so 
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views 
            m_updateDomainMap.AddNegatedConstantsToPossibleValues();

            SchemaContext cSchemaContext = new SchemaContext(ViewTarget.QueryView, m_workSpace);
            errorLog = GenerateQueryViewForExtentAndSchemaContext(cSchemaContext, identifiers, views, entity, type, mode); 

            return errorLog; 
        } 

        // effects: Generates views for the particular cellgroup in this. Returns an 
        // error log describing the errors that were encountered (if none
        // were encountered, the ErrorLog.Count is 0). Places the generated
        // views in result
        private ErrorLog GenerateAllViews(ViewSet views, CqlIdentifiers identifiers) { 

            // Allow missing attributes for now to make entity splitting run through 
            // we cannot do this for query views in general: need to obtain the exact enumerated domain 

            if (m_config.IsNormalTracing) { 
                StringBuilder builder = new StringBuilder();
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString());
            } 

            m_config.SetTimeForFinishedActivity(PerfType.CellCreation); 
            // Check if the cellgroup is consistent and all known S constraints are 
            // satisified by the known C constraints
            Validator validator = new Validator(m_cellGroup, m_config); 
            ErrorLog errorLog = validator.Validate(m_workSpace);
            if (errorLog.Count > 0) {
                errorLog.PrintTrace();
                return errorLog; 
            }
 
            m_config.SetTimeForFinishedActivity(PerfType.KeyConstraint); 

            // We generate update views first since they perform the main 
            // validation checks
            SchemaContext sSchemaContext = new SchemaContext(ViewTarget.UpdateView,
                                                             m_workSpace);
            errorLog = GenerateViewsForSchemaContext(sSchemaContext, identifiers, views); 
            if (errorLog.Count > 0) {
                return errorLog; // If we have discovered errors here, do not generate query views 
            } 

            // Make sure that the foreign key constraints are not violated 
            if (m_config.IsValidationEnabled)
            {
                CheckForeignKeyConstraints(errorLog, m_workSpace);
            } 
            m_config.SetTimeForFinishedActivity(PerfType.ForeignConstraint);
 
            if (errorLog.Count > 0) { 
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views 
            }

            // Query views - do not allow missing attributes
            // For the S-side, we add NOT ... for each scalar constant so 
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views 
            m_updateDomainMap.AddNegatedConstantsToPossibleValues(); 

            SchemaContext cSchemaContext = new SchemaContext(ViewTarget.QueryView, m_workSpace); 
            errorLog = GenerateViewsForSchemaContext(cSchemaContext, identifiers, views);

            return errorLog;
        } 

 
        private ErrorLog GenerateQueryViewForExtentAndSchemaContext(SchemaContext schemaContext, CqlIdentifiers identifiers, ViewSet views, EntitySetBase entity, EntityTypeBase type, ViewGenerationMode mode) 
        {
            Debug.Assert(schemaContext.ViewTarget == ViewTarget.QueryView); 
            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews);

            // Keep track of the mapping exceptions that we have generated
            ErrorLog errorLog = new ErrorLog(); 

            if (m_config.IsViewTracing) { 
                Helpers.StringTraceLine(String.Empty); 
                Helpers.StringTraceLine(String.Empty);
                Helpers.FormatTraceLine("================= Generating {0} Query View for: {1} ===========================", 
                                    (mode==ViewGenerationMode.OfTypeViews)? "OfType":"OfTypeOnly",
                                    entity.Name);
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTraceLine(String.Empty); 
            }
 
            try 
            {
                // (1) view generation (checks that extents are fully mapped) 
                CellNormalizer normalizer = GetCellNormalizer(entity, schemaContext, identifiers);
                QueryRewriter queryRewriter = GenerateViewsForExtentAndType(type, normalizer, identifiers, views, mode);
            }
            catch (InternalMappingException exception) 
            {
                // All exceptions have mapping errors in them 
                Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception"); 
                errorLog.Merge(exception.ErrorLog);
            } 

            return errorLog;
        }
 

        // requires: schema refers to C-side or S-side schema for the cells 
        // inside this. if schema.IsQueryView is true, the left side of cells refers 
        // to the C side (and vice-versa for the right side)
        // effects: Generates the relevant views for the schema side and 
        // returns them. If allowMissingAttributes is true and attributes
        // are missing on the schema side, substitutes them with NULL
        // Modifies views to contain the generated views for different
        // extents specified by cells and the the schemaContext 
        private ErrorLog GenerateViewsForSchemaContext(SchemaContext schemaContext, CqlIdentifiers identifiers, ViewSet views) {
 
            bool isQueryView = schemaContext.ViewTarget == ViewTarget.QueryView; 
            // Create an object that partition cells by extent
 
            KeyToListMap extentCellMap = GroupCellsByExtent(m_cellGroup, schemaContext.ViewTarget);

            // Keep track of the mapping exceptions that we have generated
            ErrorLog errorLog = new ErrorLog(); 

            // Generate views for each extent 
            foreach (EntitySetBase extent in extentCellMap.Keys) { 
                if (m_config.IsViewTracing) {
                    Helpers.StringTraceLine(String.Empty); 
                    Helpers.StringTraceLine(String.Empty);
                    Helpers.FormatTraceLine("================= Generating {0} View for: {1} ===========================",
                                     isQueryView ? "Query" : "Update", extent.Name);
                    Helpers.StringTraceLine(String.Empty); 
                    Helpers.StringTraceLine(String.Empty);
                } 
                try { 

                    // (1) view generation (checks that extents are fully mapped) 
                    QueryRewriter queryRewriter = GenerateViewsForExtent(schemaContext, extent, identifiers, views);

                    // (2) validation for update views
                    if (schemaContext.ViewTarget == ViewTarget.UpdateView && 
                        m_config.IsValidationEnabled)
                    { 
                        if (m_config.IsViewTracing) { 
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty); 
                            Helpers.FormatTraceLine("----------------- Validation for generated update view for: {0} -----------------",
                                             extent.Name);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty); 
                        }
 
                        RewritingValidator validator = new RewritingValidator(queryRewriter.Normalizer, queryRewriter.BasicView); 
                        validator.Validate();
 
                        // CQT-based validation
                        //try
                        //{
                        //    MappingValidation.RunValidation(extentCellMap.ListForKey(extent), views, m_workSpace, errorLog); 
                        //}
                        //catch (Exception) { } 
                    } 

                } catch (InternalMappingException exception) { 
                    // All exceptions have mapping errors in them
                    Debug.Assert(exception.ErrorLog.Count > 0,
                                 "Incorrectly created mapping exception");
                    errorLog.Merge(exception.ErrorLog); 
                }
            } 
            return errorLog; 
        }
 
        // effects: Given a container, ensures that all entity/association
        // sets in container on the C-side have been mapped
        private static ErrorLog EnsureAllCSpaceContainerSetsAreMapped(IEnumerable cells,
                                                                      ConfigViewGenerator config, 
                                                                      StorageEntityContainerMapping containerMapping) {
 
            Set mappedExtents = new Set(); 
            string mslFileLocation = null;
            EntityContainer container = null; 
            // Determine the container and name of the file while determining
            // the set of mapped extents in the cells
            foreach (Cell cell in cells) {
                mappedExtents.Add(cell.CQuery.Extent); 
                mslFileLocation = cell.CellLabel.SourceLocation;
                // All cells are from the same container 
                container = cell.CQuery.Extent.EntityContainer; 
            }
            Debug.Assert(container != null); 

            List missingExtents = new List();
            // Go through all the extents in the container and determine
            // extents that are missing 
            foreach (EntitySetBase extent in container.BaseEntitySets) {
                if (mappedExtents.Contains(extent) == false 
                    && !(containerMapping.HasQueryViewForSetMap(extent.Name))) { 
                    missingExtents.Add(extent);
                } 
            }
            ErrorLog errorLog = new ErrorLog();
            // If any extent is not mapped, add an error
            if (missingExtents.Count > 0) { 
                StringBuilder extentBuilder = new StringBuilder();
                bool isFirst = true; 
                foreach (EntitySetBase extent in missingExtents) { 
                    if (isFirst == false) {
                        extentBuilder.Append(", "); 
                    }
                    isFirst = false;
                    extentBuilder.Append(extent.Name);
                } 
                string message = System.Data.Entity.Strings.ViewGen_Missing_Set_Mapping_0(extentBuilder);
                // Find the cell with smallest line number - so that we can 
                // point to the beginning of the file 
                int lowestLineNum = -1;
                Cell smallestCell = null; 
                foreach (Cell cell in cells) {
                    if (lowestLineNum == -1 || cell.CellLabel.StartLineNumber < lowestLineNum) {
                        smallestCell = cell;
                        lowestLineNum = cell.CellLabel.StartLineNumber; 
                    }
                } 
                Debug.Assert(smallestCell != null && lowestLineNum >= 0); 
                EdmSchemaError edmSchemaError = new EdmSchemaError(message, (int)ViewGenErrorCode.MissingExtentMapping,
                    EdmSchemaErrorSeverity.Error, containerMapping.SourceLocation, containerMapping.StartLineNumber, 
                    containerMapping.StartLinePosition, null);
                ErrorLog.Record record = new ErrorLog.Record(edmSchemaError);
                errorLog.AddEntry(record);
            } 
            return errorLog;
        } 
 
        // effects: Given all the cells for a container, groups the cells by
        // the left query's extent and returns a dictionary for it 
        private static KeyToListMap GroupCellsByExtent(IEnumerable cells, ViewTarget viewTarget) {

            // Partition cells by extent -- extent is the top node in
            // the tree. Even for compositions for now? CHANGE_[....]_FEATURE_COMPOSITION 
            KeyToListMap extentCellMap =
                new KeyToListMap(EqualityComparer.Default); 
            foreach (Cell cell in cells) { 
                // Get the cell query and determine its extent
                CellQuery cellQuery = cell.GetLeftQuery(viewTarget); 
                extentCellMap.Add(cellQuery.Extent, cell);
            }
            return extentCellMap;
        } 

        // effects: Generates a view for an extent "extent" that belongs to 
        // schema "schema". extentCells are the cells for this extent. 
        // Adds the view corrsponding to the extent to "views"
        private QueryRewriter GenerateViewsForExtent(SchemaContext schemaContext, EntitySetBase extent, CqlIdentifiers identifiers, 
                                            ViewSet views) {

            // First normalize the cells in terms of multiconstants, etc
            // and then generate the view for the extent 
            CellNormalizer normalizer = GetCellNormalizer(extent, schemaContext, identifiers);
            QueryRewriter queryRewriter = null; 
 
            if (m_config.GenerateViewsForEachType) {
                // generate views for each OFTYPE(Extent, Type) combination 
                foreach (EdmType type in MetadataHelper.GetTypeAndSubtypesOf(extent.ElementType, m_workSpace, false /*includeAbstractTypes*/))
                {
                    if (m_config.IsViewTracing  && false == type.Equals(extent.ElementType)) {
                        Helpers.FormatTraceLine("CQL View for {0} and type {1}", extent.Name, type.Name); 
                    }
                    queryRewriter = GenerateViewsForExtentAndType(type, normalizer, identifiers, views, ViewGenerationMode.OfTypeViews); 
                } 
            } else {
                // generate the view for Extent only 
                queryRewriter = GenerateViewsForExtentAndType(extent.ElementType, normalizer, identifiers, views, ViewGenerationMode.OfTypeViews);
            }
            if (schemaContext.ViewTarget == ViewTarget.QueryView) {
                m_config.SetTimeForFinishedActivity(PerfType.QueryViews); 
            } else {
                m_config.SetTimeForFinishedActivity(PerfType.UpdateViews); 
            } 

            // cache this rewriter (and normalizer inside it) for future use in FK checking 
            m_queryRewriterMap[extent] = queryRewriter;
            return queryRewriter;
        }
 
        // effects: Returns a normalizer corresponding to extent (if one does
        // not exist, creates one) 
        private CellNormalizer GetCellNormalizer(EntitySetBase extent, SchemaContext schemaContext, CqlIdentifiers identifiers) { 
            QueryRewriter queryRewriter;
            if (false == m_queryRewriterMap.TryGetValue(extent, out queryRewriter)) 
            {
                // collect the cells that belong to this extent (just a few of them since we segment the mapping first)
                List extentCells = new List();
                foreach (Cell cell in m_cellGroup) 
                {
 
                    if (extent == cell.GetLeftQuery(schemaContext.ViewTarget).Extent) 
                    {
                        extentCells.Add(cell); 
                    }
                }
                CellNormalizer normalizer = new CellNormalizer(extent, extentCells, schemaContext, identifiers, m_config,
                                                m_queryDomainMap, m_updateDomainMap, m_entityContainerMapping, m_workSpace); 

                return normalizer; 
            } 
            else
            { 
                return queryRewriter.Normalizer;
            }
        }
 
        // effects: Generates a view for an OFTYPE(Extent, Type). The Type
        // parameter is in "normalizer.GeneratedType".  Normalizer allows 
        // obtaining the type-specific signatures and multiconstants as 
        // SignaturesForType and MultiConstantDomainForType, respectively.
        // Adds the view corrsponding to the normalizer.Extent to "views". 
        private QueryRewriter GenerateViewsForExtentAndType(EdmType generatedType, CellNormalizer normalizer, CqlIdentifiers identifiers, ViewSet views, ViewGenerationMode mode) {

            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews, "By definition this method can not handle generating views for all extents");
 
            QueryRewriter queryRewriter = new QueryRewriter(generatedType, normalizer, mode);
            queryRewriter.GenerateViewComponents(); 
 
            // Get the basic view
            CellTreeNode basicView = queryRewriter.BasicView; 

            if (m_config.IsNormalTracing) {
                Helpers.StringTrace("Basic View: ");
                Helpers.StringTraceLine(basicView.ToString()); 
            }
 
            CellTreeNode simplifiedView = GenerateSimplifiedView(basicView, queryRewriter.UsedCells); 

            if (m_config.IsNormalTracing) { 
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTrace("Simplified View: ");
                Helpers.StringTraceLine(simplifiedView.ToString());
            } 

            CqlGenerator cqlGen = new CqlGenerator(simplifiedView, queryRewriter.CaseStatements, identifiers, 
                                                   normalizer.MemberMaps.ProjectedSlotMap, 
                                                   queryRewriter.UsedCells.Count, queryRewriter.TopLevelWhereClause,
                                                   m_workSpace); 
            string viewString = cqlGen.GenerateCql();

            GeneratedView generatedView = new GeneratedView(normalizer.Extent, generatedType,
                                                            viewString, m_workSpace, m_config); 
            views.Add(normalizer.Extent, generatedView);
 
            return queryRewriter; 
        }
 
        private CellTreeNode GenerateSimplifiedView(CellTreeNode basicView, List usedCells)
        {
            Debug.Assert(false == basicView.IsEmptyRightFragmentQuery, "Basic view is empty?");
 
            // create 'joined' variables, one for each cell
            // We know (say) that out of the 10 cells that we were given, only 7 (say) were 
            // needed to construct the view for this extent. 
            int numBoolVars = usedCells.Count;
            // We need the boolean expressions in Simplify. Precisely ont boolean expression is set to 
            // true in each cell query

            for (int i = 0; i < numBoolVars; i++)
            { 
                // In the ith cell, set its boolean to be true (i.e., ith boolean)
                usedCells[i].RightCellQuery.InitializeBoolExpressions(numBoolVars, i); 
            } 

            CellTreeNode simplifiedView = Simplifier.Simplify(basicView, false); 
            return simplifiedView;
        }

        private void CheckForeignKeyConstraints(ErrorLog errorLog, MetadataWorkspace workspace) { 
            // All update views have been generated. So all the cell
            // normalizers, etc are available for the cellgroup. Check for 
            // foreign key constraints 
            foreach (ForeignConstraint constraint in m_foreignKeyConstraints) {
                // get the normalizer for the both tables 
                QueryRewriter childRewriter = null;
                QueryRewriter parentRewriter = null;
                m_queryRewriterMap.TryGetValue(constraint.ChildTable, out childRewriter);
                m_queryRewriterMap.TryGetValue(constraint.ParentTable, out parentRewriter); 
                constraint.CheckConstraint(m_cellGroup, childRewriter, parentRewriter, errorLog, m_config, workspace);
            } 
        } 
        #endregion
 
        #region String Methods
        internal override void ToCompactString(StringBuilder builder) {
            Cell.CellsToBuilder(builder, m_cellGroup);
        } 
        #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.Common.Utils.Boolean;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Data.Mapping.ViewGeneration.Validation;
using System.Data.Mapping.ViewGeneration.QueryRewriting; 
using System.Collections.Generic;
using System.Text; 
using System.Diagnostics; 
using System.Data.Mapping.ViewGeneration.Utils;
using System.Data.Metadata.Edm; 
using System.Linq;

namespace System.Data.Mapping.ViewGeneration {
 
    using ViewSet            = KeyToListMap;
    using CellGroup          = Set; 
    using WrapperBoolExpr    = BoolExpr; 
    using WrapperTrueExpr    = TrueExpr;
    using WrapperFalseExpr   = FalseExpr; 
    using WrapperNotExpr     = NotExpr;
    using WrapperOrExpr      = OrExpr;

    // This class is responsible for generating query or update mapping 
    // views from the initial cells.
    internal class ViewGenerator : InternalBase { 
 
        #region Constructor
        // effects: Creates a ViewGenerator object that is capable of 
        // producing query or update mapping views given the relevant schema
        // given the "cells"
        private ViewGenerator(CellGroup cellGroup, ConfigViewGenerator config,
                              List foreignKeyConstraints, 
                              StorageEntityContainerMapping entityContainerMapping,
                              MetadataWorkspace workSpace ) { 
 
            m_cellGroup = cellGroup;
            m_config = config; 
            m_workSpace = workSpace;
            m_queryRewriterMap = new Dictionary();
            m_foreignKeyConstraints = foreignKeyConstraints;
            m_entityContainerMapping = entityContainerMapping; 

            Dictionary> inheritanceGraph = MetadataHelper.BuildUndirectedGraphOfTypes(m_workSpace); 
 
            // We fix all the cells at this point
            m_queryDomainMap = new MemberDomainMap(ViewTarget.QueryView, cellGroup, m_workSpace, m_config, inheritanceGraph); 
            m_updateDomainMap = new MemberDomainMap(ViewTarget.UpdateView, cellGroup, m_workSpace, m_config, inheritanceGraph);

            // We now go and fix the queryDomain map so that it has all the
            // values from the S-side as well -- this is needed for domain 
            // constraint propagation, i.e., values from the S-side get
            // propagated to te oneOfConst on the C-side. So we better get 
            // the "possiblveValues" stuff to contain those constants as well 
            m_queryDomainMap.FixQueryDomainMap(cellGroup, m_updateDomainMap);
 
            FixCellConstantDomains(ViewTarget.QueryView, cellGroup, m_queryDomainMap, m_config);
            FixCellConstantDomains(ViewTarget.UpdateView, cellGroup, m_updateDomainMap, m_config);

            // We need to simplify cell queries, yet we don't want the conditions to disappear 
            // So, add an extra value to the domain, temporarily
            MemberDomainMap queryOpenDomain = m_queryDomainMap.GetOpenDomain(); 
            MemberDomainMap updateOpenDomain = m_updateDomainMap.GetOpenDomain(); 

            // Make sure the WHERE clauses of the cells reflect the changes 
            foreach (Cell cell in cellGroup)
            {
                cell.CQuery.WhereClause.FixDomainMap(queryOpenDomain);
                cell.SQuery.WhereClause.FixDomainMap(updateOpenDomain); 
                cell.CQuery.WhereClause.ExpensiveSimplify();
                cell.SQuery.WhereClause.ExpensiveSimplify(); 
                cell.CQuery.WhereClause.FixDomainMap(m_queryDomainMap); 
                cell.SQuery.WhereClause.FixDomainMap(m_updateDomainMap);
            } 
        }

        // effects: Given the extent cells and a map for the domains of all
        // variables in it, fixes the cell constant domains of the where 
        // clauses in the left queries of cells (left is defined using viewTarget)
        private static void FixCellConstantDomains(ViewTarget viewTarget, IEnumerable extentCells, 
                                                   MemberDomainMap domainMap, ConfigViewGenerator config) { 
            foreach (Cell cell in extentCells) {
                CellQuery cellQuery = cell.GetLeftQuery(viewTarget); 
                cellQuery.FixCellConstantDomains(domainMap, viewTarget);
            }

            // Fix domains of enumerated and boolean types -- i.e., whose 
            // domains are enumerable
            domainMap.FixEnumerableDomains(config); 
        } 
        #endregion
 
        #region Fields
        // internal static ConfigViewGenerator Config = null;
        private CellGroup m_cellGroup; // The initial cells from which we produce views
        private ConfigViewGenerator m_config; // Configuration variables 
        private MemberDomainMap m_queryDomainMap;
        private MemberDomainMap m_updateDomainMap; 
        private Dictionary m_queryRewriterMap; 
        private List m_foreignKeyConstraints;
        private MetadataWorkspace m_workSpace; 

        private StorageEntityContainerMapping m_entityContainerMapping;

        #endregion 

        #region External Methods 
        // effects: Given a mappingschema object, generates the query and 
        // update mapping views for OFTYPE(Extent, Type) combinations in this schema
        // container. Returns a list of generated query and update views. 
        internal static ViewGenResults GenerateViewsForSchema(StorageEntityContainerMapping containerMapping,
                                                              MetadataWorkspace workSpace,
                                                              ConfigViewGenerator config) {
            EntityUtil.CheckArgumentNull(containerMapping, "containerMapping"); 
            EntityUtil.CheckArgumentNull(config, "config");
 
            CellCreator cellCreator = new CellCreator(containerMapping, workSpace); 
            List cells = cellCreator.GenerateCells(config);
            CqlIdentifiers identifiers = cellCreator.Identifiers; 

            return GenerateViewsForSchemaCells(cells, workSpace, config, identifiers, containerMapping);
        }
 
        // effects: Given a list of cells in the schema, generates the query and
        // update mapping views for OFTYPE(Extent, Type) combinations in this schema 
        // container. Returns a list of generated query and update views. 
        // If it is false and some columns in a table are unmapped, an
        // exception is raised 
        internal static ViewGenResults GenerateViewsForSchemaCells(List cells, MetadataWorkspace workSpace,
                                                                   ConfigViewGenerator config,
                                                                   CqlIdentifiers identifiers,
                                                                   StorageEntityContainerMapping containerMapping) { 

            EntityUtil.CheckArgumentNull(cells, "cells"); 
            EntityUtil.CheckArgumentNull(config, "config"); 
            Debug.Assert(cells.Count > 0, "There must be at least one cell in the container mapping");
 
            // CHANGE_[....]_DESIGN: Derive S keys and store them away --
            // validation. From this point on, only use that key information

            // Go through each table and determine their foreign key constraints 
            EntityContainer container = containerMapping.StorageEntityContainer;
 
            Debug.Assert(container != null); 

            ViewGenResults viewGenResults = new ViewGenResults(); 
            ErrorLog tmpLog = EnsureAllCSpaceContainerSetsAreMapped(cells, config, containerMapping);
            if (tmpLog.Count > 0) {
                viewGenResults.AddErrors(tmpLog);
                Helpers.StringTraceLine(viewGenResults.ErrorsToString()); 
                return viewGenResults;
            } 
 
            List foreignKeyConstraints = ForeignConstraint.GetForeignConstraints(container, workSpace);
 
            CellPartitioner partitioner = new CellPartitioner(cells, foreignKeyConstraints);
            List cellGroups = partitioner.GroupRelatedCells();
            foreach (CellGroup cellGroup in cellGroups) {
                ViewGenerator viewGenerator = null; 
                ErrorLog groupErrorLog = new ErrorLog();
                try { 
                    viewGenerator = new ViewGenerator(cellGroup, config, foreignKeyConstraints, containerMapping, workSpace); 
                } catch (InternalMappingException exception) {
                    // All exceptions have mapping errors in them 
                    Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                    groupErrorLog = exception.ErrorLog;
                }
 
                if (groupErrorLog.Count == 0) {
                    Debug.Assert(viewGenerator != null); 
                    groupErrorLog = viewGenerator.GenerateAllViews(viewGenResults.Views, identifiers); 
                }
 
                if (groupErrorLog.Count != 0) {
                    viewGenResults.AddErrors(groupErrorLog);
                }
            } 
            // We used to print the errors here. Now we trace them as they are being thrown
            //if (viewGenResults.HasErrors && config.IsViewTracing) { 
            //    Helpers.StringTraceLine(viewGenResults.ErrorsToString()); 
            //}
            return viewGenResults; 
        }


        internal static ViewGenResults GenerateQueryViewOfType(StorageEntityContainerMapping containerMapping, 
                                                              MetadataWorkspace workSpace,
                                                              ConfigViewGenerator config, 
                                                              EntitySetBase entity, 
                                                              EntityTypeBase type,
                                                              bool includeSubtypes, 
                                                              out bool success)
        {
            EntityUtil.CheckArgumentNull(containerMapping, "containerMapping");
            EntityUtil.CheckArgumentNull(config, "config"); 
            EntityUtil.CheckArgumentNull(entity, "entity");
            EntityUtil.CheckArgumentNull(type, "type"); 
            Debug.Assert(!type.Abstract, "Can not generate OfType/OfTypeOnly query view for and abstract type"); 

            if (config.IsNormalTracing) 
            {
                Helpers.StringTraceLine("");
                Helpers.StringTraceLine("<<<<<<<< Generating Query View for Entity [" + entity.Name + "] OfType" + (includeSubtypes ? "" : "Only") + "(" + type.Name + ") >>>>>>>");
            } 

            if (containerMapping.GetEntitySetMapping(entity.Name).QueryView != null) 
            { 
                //Type-specific QV does not exist in the cache, but
                // there is a EntitySet QV. So we can't generate the view (no mapping exists for this EntitySet) 
                // and we rely on Query to call us again to get the EntitySet View.
                success = false;
                return null;
            } 

            //Compute Cell Groups or get it from Memoizer 
            InputForComputingCellGroups args = new InputForComputingCellGroups(containerMapping, config); 

            OutputFromComputeCellGroups result = containerMapping.GetCellgroups(args); 
            success = result.Success;

            if (!success)
            { 
                return null;
            } 
 
            List foreignKeyConstraints = result.ForeignKeyConstraints;
            // Get a Clone of cell groups from cache since cells are modified during viewgen, and we dont want the cached copy to change 
            List cellGroups = cellGroups = result.CellGroups.Select(setOfcells => new CellGroup(setOfcells.Select(cell => new Cell(cell)))).ToList();
            List cells = result.Cells;
            CqlIdentifiers identifiers = result.Identifiers;
 

            ViewGenResults viewGenResults = new ViewGenResults(); 
            ErrorLog tmpLog = EnsureAllCSpaceContainerSetsAreMapped(cells, config, containerMapping); 
            if (tmpLog.Count > 0)
            { 
                viewGenResults.AddErrors(tmpLog);
                Helpers.StringTraceLine(viewGenResults.ErrorsToString());
                success = true; //atleast we tried successfully
                return viewGenResults; 
            }
 
            foreach (CellGroup cellGroup in cellGroups) 
            {
                if (!DoesGroupContainExtent(cellGroup, entity)) 
                {
                    continue;
                }
 
                ViewGenerator viewGenerator = null;
                ErrorLog groupErrorLog = new ErrorLog(); 
                try 
                {
                    viewGenerator = new ViewGenerator(cellGroup, config, foreignKeyConstraints, containerMapping, workSpace); 
                }
                catch (InternalMappingException exception)
                {
                    // All exceptions have mapping errors in them 
                    Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                    groupErrorLog = exception.ErrorLog; 
                } 

                if (groupErrorLog.Count > 0) 
                {
                    break;
                }
                Debug.Assert(viewGenerator != null); //make sure there is no exception thrown that does not add error to log 

                ViewGenerationMode mode = includeSubtypes?ViewGenerationMode.OfTypeViews: ViewGenerationMode.OfTypeOnlyViews; 
 
                groupErrorLog = viewGenerator.GenerateQueryViewForSingleExtent(viewGenResults.Views, identifiers, entity, type, mode);
 
                if (groupErrorLog.Count != 0)
                {
                    viewGenResults.AddErrors(groupErrorLog);
                } 
            }
 
            success = true; 
            return viewGenResults;
        } 

        #endregion

        #region Private Methods 

        private static bool DoesGroupContainExtent(CellGroup group, EntitySetBase entity) 
        { 
            foreach(Cell cell in group)
            { 
                if (cell.GetLeftQuery(ViewTarget.QueryView).Extent.Equals(entity))
                {
                    return true;
                } 
            }
 
            return false; 
        }
 
        private ErrorLog GenerateQueryViewForSingleExtent(ViewSet views, CqlIdentifiers identifiers, EntitySetBase entity, EntityTypeBase type, ViewGenerationMode mode)
        {
            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews);
 
            if (m_config.IsNormalTracing)
            { 
                StringBuilder builder = new StringBuilder(); 
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString()); 
            }

            // Check if the cellgroup is consistent and all known S constraints are
            // satisified by the known C constraints 
            Validator validator = new Validator(m_cellGroup, m_config);
            ErrorLog errorLog = validator.Validate(m_workSpace); 
            if (errorLog.Count > 0) 
            {
                errorLog.PrintTrace(); 
                return errorLog;
            }

            // Make sure that the foreign key constraints are not violated 
            if (m_config.IsValidationEnabled)
            { 
                CheckForeignKeyConstraints(errorLog, m_workSpace); 
            }
 
            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views 
            }
 
            // For the S-side, we add NOT ... for each scalar constant so 
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views 
            m_updateDomainMap.AddNegatedConstantsToPossibleValues();

            SchemaContext cSchemaContext = new SchemaContext(ViewTarget.QueryView, m_workSpace);
            errorLog = GenerateQueryViewForExtentAndSchemaContext(cSchemaContext, identifiers, views, entity, type, mode); 

            return errorLog; 
        } 

        // effects: Generates views for the particular cellgroup in this. Returns an 
        // error log describing the errors that were encountered (if none
        // were encountered, the ErrorLog.Count is 0). Places the generated
        // views in result
        private ErrorLog GenerateAllViews(ViewSet views, CqlIdentifiers identifiers) { 

            // Allow missing attributes for now to make entity splitting run through 
            // we cannot do this for query views in general: need to obtain the exact enumerated domain 

            if (m_config.IsNormalTracing) { 
                StringBuilder builder = new StringBuilder();
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString());
            } 

            m_config.SetTimeForFinishedActivity(PerfType.CellCreation); 
            // Check if the cellgroup is consistent and all known S constraints are 
            // satisified by the known C constraints
            Validator validator = new Validator(m_cellGroup, m_config); 
            ErrorLog errorLog = validator.Validate(m_workSpace);
            if (errorLog.Count > 0) {
                errorLog.PrintTrace();
                return errorLog; 
            }
 
            m_config.SetTimeForFinishedActivity(PerfType.KeyConstraint); 

            // We generate update views first since they perform the main 
            // validation checks
            SchemaContext sSchemaContext = new SchemaContext(ViewTarget.UpdateView,
                                                             m_workSpace);
            errorLog = GenerateViewsForSchemaContext(sSchemaContext, identifiers, views); 
            if (errorLog.Count > 0) {
                return errorLog; // If we have discovered errors here, do not generate query views 
            } 

            // Make sure that the foreign key constraints are not violated 
            if (m_config.IsValidationEnabled)
            {
                CheckForeignKeyConstraints(errorLog, m_workSpace);
            } 
            m_config.SetTimeForFinishedActivity(PerfType.ForeignConstraint);
 
            if (errorLog.Count > 0) { 
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views 
            }

            // Query views - do not allow missing attributes
            // For the S-side, we add NOT ... for each scalar constant so 
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views 
            m_updateDomainMap.AddNegatedConstantsToPossibleValues(); 

            SchemaContext cSchemaContext = new SchemaContext(ViewTarget.QueryView, m_workSpace); 
            errorLog = GenerateViewsForSchemaContext(cSchemaContext, identifiers, views);

            return errorLog;
        } 

 
        private ErrorLog GenerateQueryViewForExtentAndSchemaContext(SchemaContext schemaContext, CqlIdentifiers identifiers, ViewSet views, EntitySetBase entity, EntityTypeBase type, ViewGenerationMode mode) 
        {
            Debug.Assert(schemaContext.ViewTarget == ViewTarget.QueryView); 
            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews);

            // Keep track of the mapping exceptions that we have generated
            ErrorLog errorLog = new ErrorLog(); 

            if (m_config.IsViewTracing) { 
                Helpers.StringTraceLine(String.Empty); 
                Helpers.StringTraceLine(String.Empty);
                Helpers.FormatTraceLine("================= Generating {0} Query View for: {1} ===========================", 
                                    (mode==ViewGenerationMode.OfTypeViews)? "OfType":"OfTypeOnly",
                                    entity.Name);
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTraceLine(String.Empty); 
            }
 
            try 
            {
                // (1) view generation (checks that extents are fully mapped) 
                CellNormalizer normalizer = GetCellNormalizer(entity, schemaContext, identifiers);
                QueryRewriter queryRewriter = GenerateViewsForExtentAndType(type, normalizer, identifiers, views, mode);
            }
            catch (InternalMappingException exception) 
            {
                // All exceptions have mapping errors in them 
                Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception"); 
                errorLog.Merge(exception.ErrorLog);
            } 

            return errorLog;
        }
 

        // requires: schema refers to C-side or S-side schema for the cells 
        // inside this. if schema.IsQueryView is true, the left side of cells refers 
        // to the C side (and vice-versa for the right side)
        // effects: Generates the relevant views for the schema side and 
        // returns them. If allowMissingAttributes is true and attributes
        // are missing on the schema side, substitutes them with NULL
        // Modifies views to contain the generated views for different
        // extents specified by cells and the the schemaContext 
        private ErrorLog GenerateViewsForSchemaContext(SchemaContext schemaContext, CqlIdentifiers identifiers, ViewSet views) {
 
            bool isQueryView = schemaContext.ViewTarget == ViewTarget.QueryView; 
            // Create an object that partition cells by extent
 
            KeyToListMap extentCellMap = GroupCellsByExtent(m_cellGroup, schemaContext.ViewTarget);

            // Keep track of the mapping exceptions that we have generated
            ErrorLog errorLog = new ErrorLog(); 

            // Generate views for each extent 
            foreach (EntitySetBase extent in extentCellMap.Keys) { 
                if (m_config.IsViewTracing) {
                    Helpers.StringTraceLine(String.Empty); 
                    Helpers.StringTraceLine(String.Empty);
                    Helpers.FormatTraceLine("================= Generating {0} View for: {1} ===========================",
                                     isQueryView ? "Query" : "Update", extent.Name);
                    Helpers.StringTraceLine(String.Empty); 
                    Helpers.StringTraceLine(String.Empty);
                } 
                try { 

                    // (1) view generation (checks that extents are fully mapped) 
                    QueryRewriter queryRewriter = GenerateViewsForExtent(schemaContext, extent, identifiers, views);

                    // (2) validation for update views
                    if (schemaContext.ViewTarget == ViewTarget.UpdateView && 
                        m_config.IsValidationEnabled)
                    { 
                        if (m_config.IsViewTracing) { 
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty); 
                            Helpers.FormatTraceLine("----------------- Validation for generated update view for: {0} -----------------",
                                             extent.Name);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty); 
                        }
 
                        RewritingValidator validator = new RewritingValidator(queryRewriter.Normalizer, queryRewriter.BasicView); 
                        validator.Validate();
 
                        // CQT-based validation
                        //try
                        //{
                        //    MappingValidation.RunValidation(extentCellMap.ListForKey(extent), views, m_workSpace, errorLog); 
                        //}
                        //catch (Exception) { } 
                    } 

                } catch (InternalMappingException exception) { 
                    // All exceptions have mapping errors in them
                    Debug.Assert(exception.ErrorLog.Count > 0,
                                 "Incorrectly created mapping exception");
                    errorLog.Merge(exception.ErrorLog); 
                }
            } 
            return errorLog; 
        }
 
        // effects: Given a container, ensures that all entity/association
        // sets in container on the C-side have been mapped
        private static ErrorLog EnsureAllCSpaceContainerSetsAreMapped(IEnumerable cells,
                                                                      ConfigViewGenerator config, 
                                                                      StorageEntityContainerMapping containerMapping) {
 
            Set mappedExtents = new Set(); 
            string mslFileLocation = null;
            EntityContainer container = null; 
            // Determine the container and name of the file while determining
            // the set of mapped extents in the cells
            foreach (Cell cell in cells) {
                mappedExtents.Add(cell.CQuery.Extent); 
                mslFileLocation = cell.CellLabel.SourceLocation;
                // All cells are from the same container 
                container = cell.CQuery.Extent.EntityContainer; 
            }
            Debug.Assert(container != null); 

            List missingExtents = new List();
            // Go through all the extents in the container and determine
            // extents that are missing 
            foreach (EntitySetBase extent in container.BaseEntitySets) {
                if (mappedExtents.Contains(extent) == false 
                    && !(containerMapping.HasQueryViewForSetMap(extent.Name))) { 
                    missingExtents.Add(extent);
                } 
            }
            ErrorLog errorLog = new ErrorLog();
            // If any extent is not mapped, add an error
            if (missingExtents.Count > 0) { 
                StringBuilder extentBuilder = new StringBuilder();
                bool isFirst = true; 
                foreach (EntitySetBase extent in missingExtents) { 
                    if (isFirst == false) {
                        extentBuilder.Append(", "); 
                    }
                    isFirst = false;
                    extentBuilder.Append(extent.Name);
                } 
                string message = System.Data.Entity.Strings.ViewGen_Missing_Set_Mapping_0(extentBuilder);
                // Find the cell with smallest line number - so that we can 
                // point to the beginning of the file 
                int lowestLineNum = -1;
                Cell smallestCell = null; 
                foreach (Cell cell in cells) {
                    if (lowestLineNum == -1 || cell.CellLabel.StartLineNumber < lowestLineNum) {
                        smallestCell = cell;
                        lowestLineNum = cell.CellLabel.StartLineNumber; 
                    }
                } 
                Debug.Assert(smallestCell != null && lowestLineNum >= 0); 
                EdmSchemaError edmSchemaError = new EdmSchemaError(message, (int)ViewGenErrorCode.MissingExtentMapping,
                    EdmSchemaErrorSeverity.Error, containerMapping.SourceLocation, containerMapping.StartLineNumber, 
                    containerMapping.StartLinePosition, null);
                ErrorLog.Record record = new ErrorLog.Record(edmSchemaError);
                errorLog.AddEntry(record);
            } 
            return errorLog;
        } 
 
        // effects: Given all the cells for a container, groups the cells by
        // the left query's extent and returns a dictionary for it 
        private static KeyToListMap GroupCellsByExtent(IEnumerable cells, ViewTarget viewTarget) {

            // Partition cells by extent -- extent is the top node in
            // the tree. Even for compositions for now? CHANGE_[....]_FEATURE_COMPOSITION 
            KeyToListMap extentCellMap =
                new KeyToListMap(EqualityComparer.Default); 
            foreach (Cell cell in cells) { 
                // Get the cell query and determine its extent
                CellQuery cellQuery = cell.GetLeftQuery(viewTarget); 
                extentCellMap.Add(cellQuery.Extent, cell);
            }
            return extentCellMap;
        } 

        // effects: Generates a view for an extent "extent" that belongs to 
        // schema "schema". extentCells are the cells for this extent. 
        // Adds the view corrsponding to the extent to "views"
        private QueryRewriter GenerateViewsForExtent(SchemaContext schemaContext, EntitySetBase extent, CqlIdentifiers identifiers, 
                                            ViewSet views) {

            // First normalize the cells in terms of multiconstants, etc
            // and then generate the view for the extent 
            CellNormalizer normalizer = GetCellNormalizer(extent, schemaContext, identifiers);
            QueryRewriter queryRewriter = null; 
 
            if (m_config.GenerateViewsForEachType) {
                // generate views for each OFTYPE(Extent, Type) combination 
                foreach (EdmType type in MetadataHelper.GetTypeAndSubtypesOf(extent.ElementType, m_workSpace, false /*includeAbstractTypes*/))
                {
                    if (m_config.IsViewTracing  && false == type.Equals(extent.ElementType)) {
                        Helpers.FormatTraceLine("CQL View for {0} and type {1}", extent.Name, type.Name); 
                    }
                    queryRewriter = GenerateViewsForExtentAndType(type, normalizer, identifiers, views, ViewGenerationMode.OfTypeViews); 
                } 
            } else {
                // generate the view for Extent only 
                queryRewriter = GenerateViewsForExtentAndType(extent.ElementType, normalizer, identifiers, views, ViewGenerationMode.OfTypeViews);
            }
            if (schemaContext.ViewTarget == ViewTarget.QueryView) {
                m_config.SetTimeForFinishedActivity(PerfType.QueryViews); 
            } else {
                m_config.SetTimeForFinishedActivity(PerfType.UpdateViews); 
            } 

            // cache this rewriter (and normalizer inside it) for future use in FK checking 
            m_queryRewriterMap[extent] = queryRewriter;
            return queryRewriter;
        }
 
        // effects: Returns a normalizer corresponding to extent (if one does
        // not exist, creates one) 
        private CellNormalizer GetCellNormalizer(EntitySetBase extent, SchemaContext schemaContext, CqlIdentifiers identifiers) { 
            QueryRewriter queryRewriter;
            if (false == m_queryRewriterMap.TryGetValue(extent, out queryRewriter)) 
            {
                // collect the cells that belong to this extent (just a few of them since we segment the mapping first)
                List extentCells = new List();
                foreach (Cell cell in m_cellGroup) 
                {
 
                    if (extent == cell.GetLeftQuery(schemaContext.ViewTarget).Extent) 
                    {
                        extentCells.Add(cell); 
                    }
                }
                CellNormalizer normalizer = new CellNormalizer(extent, extentCells, schemaContext, identifiers, m_config,
                                                m_queryDomainMap, m_updateDomainMap, m_entityContainerMapping, m_workSpace); 

                return normalizer; 
            } 
            else
            { 
                return queryRewriter.Normalizer;
            }
        }
 
        // effects: Generates a view for an OFTYPE(Extent, Type). The Type
        // parameter is in "normalizer.GeneratedType".  Normalizer allows 
        // obtaining the type-specific signatures and multiconstants as 
        // SignaturesForType and MultiConstantDomainForType, respectively.
        // Adds the view corrsponding to the normalizer.Extent to "views". 
        private QueryRewriter GenerateViewsForExtentAndType(EdmType generatedType, CellNormalizer normalizer, CqlIdentifiers identifiers, ViewSet views, ViewGenerationMode mode) {

            Debug.Assert(mode != ViewGenerationMode.GenerateAllViews, "By definition this method can not handle generating views for all extents");
 
            QueryRewriter queryRewriter = new QueryRewriter(generatedType, normalizer, mode);
            queryRewriter.GenerateViewComponents(); 
 
            // Get the basic view
            CellTreeNode basicView = queryRewriter.BasicView; 

            if (m_config.IsNormalTracing) {
                Helpers.StringTrace("Basic View: ");
                Helpers.StringTraceLine(basicView.ToString()); 
            }
 
            CellTreeNode simplifiedView = GenerateSimplifiedView(basicView, queryRewriter.UsedCells); 

            if (m_config.IsNormalTracing) { 
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTrace("Simplified View: ");
                Helpers.StringTraceLine(simplifiedView.ToString());
            } 

            CqlGenerator cqlGen = new CqlGenerator(simplifiedView, queryRewriter.CaseStatements, identifiers, 
                                                   normalizer.MemberMaps.ProjectedSlotMap, 
                                                   queryRewriter.UsedCells.Count, queryRewriter.TopLevelWhereClause,
                                                   m_workSpace); 
            string viewString = cqlGen.GenerateCql();

            GeneratedView generatedView = new GeneratedView(normalizer.Extent, generatedType,
                                                            viewString, m_workSpace, m_config); 
            views.Add(normalizer.Extent, generatedView);
 
            return queryRewriter; 
        }
 
        private CellTreeNode GenerateSimplifiedView(CellTreeNode basicView, List usedCells)
        {
            Debug.Assert(false == basicView.IsEmptyRightFragmentQuery, "Basic view is empty?");
 
            // create 'joined' variables, one for each cell
            // We know (say) that out of the 10 cells that we were given, only 7 (say) were 
            // needed to construct the view for this extent. 
            int numBoolVars = usedCells.Count;
            // We need the boolean expressions in Simplify. Precisely ont boolean expression is set to 
            // true in each cell query

            for (int i = 0; i < numBoolVars; i++)
            { 
                // In the ith cell, set its boolean to be true (i.e., ith boolean)
                usedCells[i].RightCellQuery.InitializeBoolExpressions(numBoolVars, i); 
            } 

            CellTreeNode simplifiedView = Simplifier.Simplify(basicView, false); 
            return simplifiedView;
        }

        private void CheckForeignKeyConstraints(ErrorLog errorLog, MetadataWorkspace workspace) { 
            // All update views have been generated. So all the cell
            // normalizers, etc are available for the cellgroup. Check for 
            // foreign key constraints 
            foreach (ForeignConstraint constraint in m_foreignKeyConstraints) {
                // get the normalizer for the both tables 
                QueryRewriter childRewriter = null;
                QueryRewriter parentRewriter = null;
                m_queryRewriterMap.TryGetValue(constraint.ChildTable, out childRewriter);
                m_queryRewriterMap.TryGetValue(constraint.ParentTable, out parentRewriter); 
                constraint.CheckConstraint(m_cellGroup, childRewriter, parentRewriter, errorLog, m_config, workspace);
            } 
        } 
        #endregion
 
        #region String Methods
        internal override void ToCompactString(StringBuilder builder) {
            Cell.CellsToBuilder(builder, m_cellGroup);
        } 
        #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