255 lines
9.3 KiB
C#
255 lines
9.3 KiB
C#
//---------------------------------------------------------------------
|
|
// <copyright file="Cell.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//
|
|
// @owner [....]
|
|
// @backupOwner [....]
|
|
//---------------------------------------------------------------------
|
|
|
|
using System.Data.Common.Utils;
|
|
using System.Collections.Generic;
|
|
using System.Data.Mapping.ViewGeneration.Validation;
|
|
using System.Text;
|
|
using System.Diagnostics;
|
|
using System.Data.Metadata.Edm;
|
|
|
|
namespace System.Data.Mapping.ViewGeneration.Structures
|
|
{
|
|
|
|
/// <summary>
|
|
/// This class contains a pair of cell queries which is essentially a
|
|
/// constraint that they are equal. A cell is initialized with a C or an
|
|
/// S Query which it exposes as properties but it also has the notion of
|
|
/// "Left" and "Right" queries -- left refers to the side for which a
|
|
/// view is being generated
|
|
/// For example, to
|
|
/// specify a mapping for CPerson to an SPerson table, we have
|
|
///
|
|
/// [(p type Person) in P : SPerson]
|
|
/// (p.pid, pid)
|
|
/// (p.name, name)
|
|
///
|
|
/// This really denotes the equality of two queries:
|
|
/// (C) SELECT (p type Person) AS D1, p.pid, p.name FROM p in P WHERE D1
|
|
/// (S) SELECT True AS D1, pid, name FROM SPerson WHERE D1
|
|
///
|
|
/// For more details, see the design doc
|
|
/// </summary>
|
|
internal class Cell : InternalBase
|
|
{
|
|
#region Constructor
|
|
// effects: Creates a cell with the C and S queries
|
|
private Cell(CellQuery cQuery, CellQuery sQuery, CellLabel label, int cellNumber)
|
|
{
|
|
Debug.Assert(label != null, "Cell lacks label");
|
|
m_cQuery = cQuery;
|
|
m_sQuery = sQuery;
|
|
m_label = label;
|
|
m_cellNumber = cellNumber;
|
|
Debug.Assert(m_sQuery.NumProjectedSlots == m_cQuery.NumProjectedSlots,
|
|
"Cell queries disagree on the number of projected fields");
|
|
}
|
|
/// <summary>
|
|
/// Copy Constructor
|
|
/// </summary>
|
|
internal Cell(Cell source)
|
|
{
|
|
m_cQuery = new CellQuery(source.m_cQuery);
|
|
m_sQuery = new CellQuery(source.m_sQuery);
|
|
m_label = new CellLabel(source.m_label);
|
|
m_cellNumber = source.m_cellNumber;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fields
|
|
private CellQuery m_cQuery;
|
|
private CellQuery m_sQuery;
|
|
private int m_cellNumber; // cell number that identifies this cell
|
|
private CellLabel m_label; // The File and Path Info for the CSMappingFragment
|
|
// that the Cell was constructed over.
|
|
// The view cell relation for all projected slots in this
|
|
private ViewCellRelation m_viewCellRelation;
|
|
#endregion
|
|
|
|
#region Properties
|
|
// effects: Returns the C query
|
|
internal CellQuery CQuery
|
|
{
|
|
get { return m_cQuery; }
|
|
}
|
|
|
|
// effects: Returns the S query
|
|
internal CellQuery SQuery
|
|
{
|
|
get { return m_sQuery; }
|
|
}
|
|
|
|
// effects: Returns the CSMappingFragment (if any)
|
|
// that the Cell was constructed over.
|
|
internal CellLabel CellLabel
|
|
{
|
|
get { return m_label; }
|
|
}
|
|
|
|
// effects: Returns the cell label (if any)
|
|
internal int CellNumber
|
|
{
|
|
get { return m_cellNumber; }
|
|
}
|
|
|
|
internal string CellNumberAsString
|
|
{
|
|
get { return StringUtil.FormatInvariant("V{0}", CellNumber); }
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
// effects: Determines all the identifiers used in this and adds them to identifiers
|
|
internal void GetIdentifiers(CqlIdentifiers identifiers)
|
|
{
|
|
m_cQuery.GetIdentifiers(identifiers);
|
|
m_sQuery.GetIdentifiers(identifiers);
|
|
}
|
|
|
|
// effects: Given a cell, determines the paths to which the paths in
|
|
// columns map to in the C-space and returns them. If some columns
|
|
// are not projected in the cell, or if the corresponding properties
|
|
// are not mapped into C-space, returns null
|
|
internal Set<EdmProperty> GetCSlotsForTableColumns(IEnumerable<MemberPath> columns)
|
|
{
|
|
List<int> fieldNums = SQuery.GetProjectedPositions(columns);
|
|
if (fieldNums == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// The fields are mapped -- see if they are mapped on the
|
|
// cSide and they correspond to the primary key of the
|
|
// entity set
|
|
|
|
Set<EdmProperty> cSideMembers = new Set<EdmProperty>();
|
|
foreach (int fieldNum in fieldNums)
|
|
{
|
|
ProjectedSlot projectedSlot = CQuery.ProjectedSlotAt(fieldNum);
|
|
MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot;
|
|
if (slot != null)
|
|
{
|
|
// We can call LastMember since columns do not map to
|
|
// extents or memberEnds. Can cast to EdmProperty since it
|
|
// cannot be an association end
|
|
cSideMembers.Add((EdmProperty)slot.MemberPath.LeafEdmMember);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
return cSideMembers;
|
|
}
|
|
|
|
// effects: Returns the C query for ViewTarget.QueryView and S query for ViewTarget.UpdateView
|
|
internal CellQuery GetLeftQuery(ViewTarget side)
|
|
{
|
|
return side == ViewTarget.QueryView ? m_cQuery : m_sQuery;
|
|
}
|
|
|
|
// effects: Returns the S query for ViewTarget.QueryView and C query for ViewTarget.UpdateView
|
|
internal CellQuery GetRightQuery(ViewTarget side)
|
|
{
|
|
return side == ViewTarget.QueryView ? m_sQuery : m_cQuery;
|
|
}
|
|
|
|
// effects: Returns the relation that contains all the slots being
|
|
// projected in this cell
|
|
internal ViewCellRelation CreateViewCellRelation(int cellNumber)
|
|
{
|
|
if (m_viewCellRelation != null)
|
|
{
|
|
return m_viewCellRelation;
|
|
}
|
|
GenerateCellRelations(cellNumber);
|
|
return m_viewCellRelation;
|
|
}
|
|
|
|
private void GenerateCellRelations(int cellNumber)
|
|
{
|
|
// Generate the view cell relation
|
|
List<ViewCellSlot> projectedSlots = new List<ViewCellSlot>();
|
|
// construct a ViewCellSlot for each slot
|
|
Debug.Assert(CQuery.NumProjectedSlots == SQuery.NumProjectedSlots,
|
|
"Cell queries in cell have a different number of slots");
|
|
for (int i = 0; i < CQuery.NumProjectedSlots; i++)
|
|
{
|
|
ProjectedSlot cSlot = CQuery.ProjectedSlotAt(i);
|
|
ProjectedSlot sSlot = SQuery.ProjectedSlotAt(i);
|
|
Debug.Assert(cSlot != null, "Has cell query been normalized?");
|
|
Debug.Assert(sSlot != null, "Has cell query been normalized?");
|
|
|
|
// These slots better be MemberProjectedSlots. We do not have constants etc at this point.
|
|
Debug.Assert(cSlot is MemberProjectedSlot, "cSlot is expected to be MemberProjectedSlot");
|
|
Debug.Assert(sSlot is MemberProjectedSlot, "sSlot is expected to be MemberProjectedSlot");
|
|
|
|
MemberProjectedSlot cJoinSlot = (MemberProjectedSlot)cSlot;
|
|
MemberProjectedSlot sJoinSlot = (MemberProjectedSlot)sSlot;
|
|
|
|
ViewCellSlot slot = new ViewCellSlot(i, cJoinSlot, sJoinSlot);
|
|
projectedSlots.Add(slot);
|
|
}
|
|
m_viewCellRelation = new ViewCellRelation(this, projectedSlots, cellNumber);
|
|
}
|
|
|
|
internal override void ToCompactString(StringBuilder builder)
|
|
{
|
|
CQuery.ToCompactString(builder);
|
|
builder.Append(" = ");
|
|
SQuery.ToCompactString(builder);
|
|
}
|
|
|
|
internal override void ToFullString(StringBuilder builder)
|
|
{
|
|
CQuery.ToFullString(builder);
|
|
builder.Append(" = ");
|
|
SQuery.ToFullString(builder);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return ToFullString();
|
|
}
|
|
|
|
// effects: Prints the cells in some human-readable form
|
|
internal static void CellsToBuilder(StringBuilder builder, IEnumerable<Cell> cells)
|
|
{
|
|
// Print mapping
|
|
builder.AppendLine();
|
|
builder.AppendLine("=========================================================================");
|
|
foreach (Cell cell in cells)
|
|
{
|
|
builder.AppendLine();
|
|
StringUtil.FormatStringBuilder(builder, "Mapping Cell V{0}:", cell.CellNumber);
|
|
builder.AppendLine();
|
|
|
|
builder.Append("C: ");
|
|
cell.CQuery.ToFullString(builder);
|
|
builder.AppendLine();
|
|
builder.AppendLine();
|
|
|
|
builder.Append("S: ");
|
|
cell.SQuery.ToFullString(builder);
|
|
builder.AppendLine();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Factory methods
|
|
internal static Cell CreateCS(CellQuery cQuery, CellQuery sQuery, CellLabel label, int cellNumber)
|
|
{
|
|
return new Cell(cQuery, sQuery, label, cellNumber);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|