Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / ViewGenerator.cs / 2 / 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ChangesetResponse.cs
- BindingValueChangedEventArgs.cs
- NativeCppClassAttribute.cs
- StrokeNodeEnumerator.cs
- TemplateField.cs
- StringUtil.cs
- PeekCompletedEventArgs.cs
- GeneralTransformGroup.cs
- NamespaceInfo.cs
- ExtensionSimplifierMarkupObject.cs
- ValidationPropertyAttribute.cs
- CalendarDay.cs
- QueryOptionExpression.cs
- SerializationInfoEnumerator.cs
- RelationshipConverter.cs
- VirtualDirectoryMappingCollection.cs
- X509SecurityToken.cs
- Control.cs
- ServiceNameElementCollection.cs
- GroupQuery.cs
- Exceptions.cs
- SessionPageStateSection.cs
- BinaryObjectWriter.cs
- UIElementCollection.cs
- ThreadPool.cs
- Vector3DCollectionValueSerializer.cs
- CustomAttribute.cs
- SelectionRangeConverter.cs
- LineMetrics.cs
- MsmqEncryptionAlgorithm.cs
- DataQuery.cs
- EntityDataSourceViewSchema.cs
- TextBoxRenderer.cs
- SQlBooleanStorage.cs
- ResolveNameEventArgs.cs
- DataControlField.cs
- NullExtension.cs
- XmlTextEncoder.cs
- SafeProcessHandle.cs
- TableRow.cs
- DetailsViewModeEventArgs.cs
- ChannelBinding.cs
- TextDecorations.cs
- XmlChildEnumerator.cs
- TextTreeTextElementNode.cs
- Compiler.cs
- ClientSideQueueItem.cs
- LocatorManager.cs
- ListenerElementsCollection.cs
- RMEnrollmentPage2.cs
- ServerTooBusyException.cs
- SQLResource.cs
- AttributeCollection.cs
- TreeNodeStyleCollection.cs
- FirstQueryOperator.cs
- ServicePoint.cs
- XmlWrappingReader.cs
- Italic.cs
- Util.cs
- CalculatedColumn.cs
- IndexedEnumerable.cs
- StreamWriter.cs
- ModuleConfigurationInfo.cs
- BindingManagerDataErrorEventArgs.cs
- loginstatus.cs
- ColorAnimationUsingKeyFrames.cs
- SizeAnimationBase.cs
- TextBounds.cs
- CollectionView.cs
- TableRowCollection.cs
- IsolatedStorage.cs
- SliderAutomationPeer.cs
- InternalTypeHelper.cs
- BatchWriter.cs
- HitTestFilterBehavior.cs
- SchemaImporterExtensionElementCollection.cs
- Switch.cs
- StringSource.cs
- PixelFormat.cs
- MenuItemBindingCollection.cs
- VariableQuery.cs
- PointLight.cs
- StylusCollection.cs
- UIElement3DAutomationPeer.cs
- MenuItem.cs
- ScriptIgnoreAttribute.cs
- ListCollectionView.cs
- ContentElementAutomationPeer.cs
- HttpPostedFileWrapper.cs
- MediaPlayerState.cs
- XmlILStorageConverter.cs
- DescendantQuery.cs
- arc.cs
- CheckoutException.cs
- GlyphShapingProperties.cs
- IsolatedStoragePermission.cs
- HtmlElementCollection.cs
- filewebresponse.cs
- ToolStripDropDownItem.cs
- SymbolEqualComparer.cs