1 //---------------------------------------------------------------------
2 // <copyright file="CellPartioner.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Data.Common.Utils;
12 using System.Data.Mapping.ViewGeneration.Structures;
13 using System.Collections.Generic;
14 using System.Data.Mapping.ViewGeneration.Validation;
16 using System.Data.Mapping.Update.Internal;
17 using System.Collections.ObjectModel;
18 using System.Data.Metadata.Edm;
20 namespace System.Data.Mapping.ViewGeneration
23 using CellGroup = Set<Cell>;
25 // This class is responsible for partitioning cells into groups of cells
26 // that are related and for which view generation needs to be done together
27 internal class CellPartitioner : InternalBase
31 // effects: Creates a partitioner for cells with extra information
32 // about foreign key constraints
33 internal CellPartitioner(IEnumerable<Cell> cells, IEnumerable<ForeignConstraint> foreignKeyConstraints)
35 m_foreignKeyConstraints = foreignKeyConstraints;
41 private IEnumerable<Cell> m_cells;
42 private IEnumerable<ForeignConstraint> m_foreignKeyConstraints;
45 #region Available Methods
46 // effects: Given a list of cells, segments them into multiple
47 // "groups" such that view generation (including validation) of one
48 // group can be done independently of another group. Returns the
49 // groups as a list (uses the foreign key information as well)
50 internal List<CellGroup> GroupRelatedCells()
52 // If two cells share the same C or S, we place them in the same group
53 // For each cell, determine the Cis and Sis that it refers
54 // to. For every Ci (Si), keep track of the cells that Ci is
55 // contained in. At the end, run through the Cis and Sis and do a
56 // "connected components" algorithm to determine partitions
58 // Now form a graph between different cells -- then compute the connected
60 UndirectedGraph<Cell> graph = new UndirectedGraph<Cell>(EqualityComparer<Cell>.Default);
62 List<Cell> alreadyAddedCells = new List<Cell>();
63 // For each extent, add an edge between it and all previously
64 // added extents with which it overlaps
66 foreach (Cell cell in m_cells)
68 graph.AddVertex(cell);
69 // Add an edge from this cell to the already added cells
70 EntitySetBase firstCExtent = cell.CQuery.Extent;
71 EntitySetBase firstSExtent = cell.SQuery.Extent;
72 foreach (Cell existingCell in alreadyAddedCells)
74 EntitySetBase secondCExtent = existingCell.CQuery.Extent;
75 EntitySetBase secondSExtent = existingCell.SQuery.Extent;
77 // Add an edge between cell and existingCell if
78 // * They have the same C or S extent
79 // * They are linked via a foreign key between the S extents
80 // * They are linked via a relationship
81 bool sameExtent = secondCExtent.Equals(firstCExtent) || secondSExtent.Equals(firstSExtent);
82 bool linkViaForeignKey = OverlapViaForeignKeys(cell, existingCell);
83 bool linkViaRelationship = AreCellsConnectedViaRelationship(cell, existingCell);
85 if (sameExtent || linkViaForeignKey || linkViaRelationship)
87 graph.AddEdge(existingCell, cell);
90 alreadyAddedCells.Add(cell);
93 // Now determine the connected components of this graph
94 List<CellGroup> result = GenerateConnectedComponents(graph);
99 #region Private Methods
101 // effects: Returns true iff cell1 is an extent at the end of cell2's
102 // relationship set or vice versa
103 private static bool AreCellsConnectedViaRelationship(Cell cell1, Cell cell2)
105 AssociationSet cRelationSet1 = cell1.CQuery.Extent as AssociationSet;
106 AssociationSet cRelationSet2 = cell2.CQuery.Extent as AssociationSet;
107 if (cRelationSet1 != null && MetadataHelper.IsExtentAtSomeRelationshipEnd(cRelationSet1, cell2.CQuery.Extent))
111 if (cRelationSet2 != null && MetadataHelper.IsExtentAtSomeRelationshipEnd(cRelationSet2, cell1.CQuery.Extent))
117 // effects: Given a graph of cell groups, returns a list of cellgroup
118 // such that each cellgroup contains all the cells that are in the
119 // same connected component
120 private static List<CellGroup> GenerateConnectedComponents(UndirectedGraph<Cell> graph)
122 KeyToListMap<int, Cell> groupMap = graph.GenerateConnectedComponents();
124 // Run through the list of groups and generate the merged groups
125 List<CellGroup> result = new List<CellGroup>();
126 foreach (int setNum in groupMap.Keys)
128 ReadOnlyCollection<Cell> cellsInComponent = groupMap.ListForKey(setNum);
129 CellGroup component = new CellGroup(cellsInComponent);
130 result.Add(component);
135 // effects: Returns true iff there is a foreign key constraint
136 // between cell1 and cell2's S extents
137 private bool OverlapViaForeignKeys(Cell cell1, Cell cell2)
139 EntitySetBase sExtent1 = cell1.SQuery.Extent;
140 EntitySetBase sExtent2 = cell2.SQuery.Extent;
142 foreach (ForeignConstraint constraint in m_foreignKeyConstraints)
144 if (sExtent1.Equals(constraint.ParentTable) && sExtent2.Equals(constraint.ChildTable) ||
145 sExtent2.Equals(constraint.ParentTable) && sExtent1.Equals(constraint.ChildTable))
154 internal override void ToCompactString(StringBuilder builder)
156 Cell.CellsToBuilder(builder, m_cells);