Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / ViewGenerator.cs / 1 / 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
- BitmapEffectDrawingContent.cs
- AQNBuilder.cs
- LinearGradientBrush.cs
- TileBrush.cs
- BindingElementCollection.cs
- SizeAnimation.cs
- EarlyBoundInfo.cs
- StringUtil.cs
- DataColumnMapping.cs
- LicenseException.cs
- Point3DConverter.cs
- XmlDataCollection.cs
- XMLSyntaxException.cs
- ObjectDataSourceFilteringEventArgs.cs
- ToolStripManager.cs
- Pens.cs
- _TLSstream.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- AdapterDictionary.cs
- SingleAnimation.cs
- WizardForm.cs
- COM2IDispatchConverter.cs
- TextEditorThreadLocalStore.cs
- SqlColumnizer.cs
- Encoder.cs
- ServiceOperationParameter.cs
- ClassHandlersStore.cs
- ColorComboBox.cs
- DataControlLinkButton.cs
- OleDbTransaction.cs
- PackageProperties.cs
- DefaultValueConverter.cs
- TypeSource.cs
- ResourceProperty.cs
- ToolStripItemImageRenderEventArgs.cs
- ObjectDataSourceDesigner.cs
- StringUtil.cs
- RelativeSource.cs
- IdentityElement.cs
- ToolStripItem.cs
- DataGridSortCommandEventArgs.cs
- CollectionContainer.cs
- PropertyChange.cs
- JsonXmlDataContract.cs
- CodeCastExpression.cs
- WrapPanel.cs
- BufferedGraphicsContext.cs
- AnonymousIdentificationSection.cs
- XmlBindingWorker.cs
- TemplatePartAttribute.cs
- ActivityExecutionContext.cs
- MetaModel.cs
- XmlDocumentFragment.cs
- BuildResult.cs
- RootContext.cs
- SourceLineInfo.cs
- StringKeyFrameCollection.cs
- DefaultProxySection.cs
- GeneralTransformGroup.cs
- PathSegmentCollection.cs
- IsolatedStorageFile.cs
- SplayTreeNode.cs
- Line.cs
- fixedPageContentExtractor.cs
- Propagator.JoinPropagator.JoinPredicateVisitor.cs
- View.cs
- InstalledFontCollection.cs
- EnumCodeDomSerializer.cs
- PluggableProtocol.cs
- PolicyImporterElementCollection.cs
- MediaCommands.cs
- DocumentXPathNavigator.cs
- HeaderFilter.cs
- PropertyEmitterBase.cs
- TextFormatter.cs
- CommonDialog.cs
- TypeUtil.cs
- CodeBlockBuilder.cs
- FormViewUpdatedEventArgs.cs
- Single.cs
- Win32Exception.cs
- Rectangle.cs
- WebPartPersonalization.cs
- DrawingGroupDrawingContext.cs
- Visual.cs
- StorageFunctionMapping.cs
- SelectionHighlightInfo.cs
- MethodToken.cs
- coordinator.cs
- WmfPlaceableFileHeader.cs
- DataGridViewIntLinkedList.cs
- DataGridSortCommandEventArgs.cs
- KeyTimeConverter.cs
- MobileCategoryAttribute.cs
- FakeModelItemImpl.cs
- InputLangChangeEvent.cs
- SqlIdentifier.cs
- DecoderNLS.cs
- Win32Exception.cs
- EditorBrowsableAttribute.cs