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 / Query / PlanCompiler / ColumnMapProcessor.cs / 1 / ColumnMapProcessor.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....], [....]
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Common.Utils;
using md = System.Data.Metadata.Edm;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
using System.Globalization;
namespace System.Data.Query.PlanCompiler {
internal class ColumnMapProcessor {
#region "public" methods
internal ColumnMap ExpandColumnMap() {
// special handling for the case when the top-level var is a collection.
// The element type of the collection may have changed, and consequently a new
// var will have been created. We simply create a columnmap with that var.
CollectionVarInfo collectionVarInfo = m_varInfo as CollectionVarInfo;
if (collectionVarInfo != null) {
return new VarRefColumnMap(m_columnMap.Var.Type, m_columnMap.Name, collectionVarInfo.NewVar);
}
else {
return this.CreateColumnMap(m_columnMap.Var.Type, m_columnMap.Name);
}
}
#endregion
#region Constructors
internal ColumnMapProcessor(VarRefColumnMap columnMap, VarInfo varInfo, StructuredTypeInfo typeInfo) {
m_columnMap = columnMap;
m_varInfo = varInfo;
PlanCompiler.Assert(varInfo.NewVars != null && varInfo.NewVars.Count > 0, "No new Vars specified");
m_varList = varInfo.NewVars.GetEnumerator();
m_typeInfo = typeInfo;
}
#endregion
#region private state
private IEnumerator m_varList;
private VarInfo m_varInfo;
private VarRefColumnMap m_columnMap;
private StructuredTypeInfo m_typeInfo;
private const string c_TypeIdColumnName = "__TypeId"; // name of the typeid column
private const string c_EntitySetIdColumnName = "__EntitySetId"; // name of the entityset column
private const string c_NullSentinelColumnName = "__NullSentinel"; // name of the nullability column
#endregion
#region private methods
private Var GetNextVar() {
if (m_varList.MoveNext()) {
return m_varList.Current;
}
PlanCompiler.Assert(false, "Could not GetNextVar");
return null;
}
///
/// Creates a column map for a column
///
/// column datatype
/// column name
///
private ColumnMap CreateColumnMap(md.TypeUsage type, string name) {
// For simple types, create a simple column map
// Temporarily, handle collections exactly the same way
if (!TypeUtils.IsStructuredType(type)) {
return CreateSimpleColumnMap(type, name);
}
// At this point, we must be dealing with either a record type, a
// complex type, or an entity type
return CreateStructuralColumnMap(type, name);
}
///
/// Create a column map for a complextype column
///
/// Type information for the type
/// column name
/// Supertype info if any
/// Dictionary of typeidvalue->column map
/// List of all maps
///
private ComplexTypeColumnMap CreateComplexTypeColumnMap(TypeInfo typeInfo, string name, ComplexTypeColumnMap superTypeColumnMap,
Dictionary discriminatorMap, List allMaps) {
List propertyColumnMapList = new List();
IEnumerable myProperties = null;
SimpleColumnMap nullSentinelColumnMap = null;
if (typeInfo.HasNullSentinelProperty) {
nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName);
}
// Copy over information from my supertype if it already exists
if (superTypeColumnMap != null) {
foreach (ColumnMap c in superTypeColumnMap.Properties) {
propertyColumnMapList.Add(c);
}
myProperties = TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type);
}
else {
// need to get all members otherwise
myProperties = TypeHelpers.GetAllStructuralMembers(typeInfo.Type);
}
// Now add on all of my "specific" properties
foreach (md.EdmMember property in myProperties) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
}
// Create a map for myself
ComplexTypeColumnMap columnMap = new ComplexTypeColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), nullSentinelColumnMap);
// if a dictionary is supplied, add myself to the dictionary
if (discriminatorMap != null) {
discriminatorMap[typeInfo.TypeId] = columnMap;
}
if (allMaps != null) {
allMaps.Add(columnMap);
}
// Finally walk through my subtypes - use the same column name
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
CreateComplexTypeColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps);
}
return columnMap;
}
///
/// Create a column map for an entitytype column.
/// Currently, the key columns are not duplicated (ie) they point into the
/// same locations as in the properties list.
/// Note: we also don't handle keys that are properties of nested fields
///
/// Type information for the type
/// column name
/// supertype information if any
/// Dictionary of typeid->column map information
/// List of all column maps (including those without typeid)
/// should we handle rel-properties?
///
private EntityColumnMap CreateEntityColumnMap(TypeInfo typeInfo, string name, EntityColumnMap superTypeColumnMap,
Dictionary discriminatorMap, List allMaps, bool handleRelProperties) {
EntityColumnMap columnMap = null;
List propertyColumnMapList = new List();
// Copy over information from my supertype if it already exists
if (superTypeColumnMap != null) {
// get supertype properties
foreach (ColumnMap c in superTypeColumnMap.Properties) {
propertyColumnMapList.Add(c);
}
// Now add on all of my "specific" properties
foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
}
// create the entity column map w/ information from my supertype
columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), superTypeColumnMap.EntityIdentity);
}
else {
SimpleColumnMap entitySetIdColumnMap = null;
if (typeInfo.HasEntitySetIdProperty) {
entitySetIdColumnMap = CreateEntitySetIdColumnMap(typeInfo.EntitySetIdProperty);
}
// build up a list of key columns
List keyColumnMapList = new List();
// Create a dictionary to look up the key properties
Dictionary keyPropertyMap = new Dictionary();
foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
// add property to keymap, if this property is part of the key
if (md.TypeSemantics.IsPartOfKey(property)) {
md.EdmProperty edmProperty = property as md.EdmProperty;
PlanCompiler.Assert(edmProperty != null, "EntityType key member is not property?");
keyPropertyMap[edmProperty] = propertyColumnMap;
}
}
// Build up the key list if required
foreach (md.EdmMember keyProperty in TypeHelpers.GetEdmType(typeInfo.Type).KeyMembers) {
md.EdmProperty edmKeyProperty = keyProperty as md.EdmProperty;
PlanCompiler.Assert(edmKeyProperty!=null, "EntityType key member is not property?");
SimpleColumnMap keyColumnMap = keyPropertyMap[edmKeyProperty] as SimpleColumnMap;
PlanCompiler.Assert(keyColumnMap != null, "keyColumnMap is null");
keyColumnMapList.Add(keyColumnMap);
}
//
// Create the entity identity.
//
EntityIdentity identity = CreateEntityIdentity((md.EntityType)typeInfo.Type.EdmType, entitySetIdColumnMap, keyColumnMapList.ToArray());
// finally create the entity column map
columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), identity);
}
// if a dictionary is supplied, add myself to the dictionary (abstract types need not be added)
if (discriminatorMap != null) {
// where DiscriminatedNewInstanceOp is used, there will not be an explicit type id for an abstract type
// or types that do not appear in the QueryView
// (the mapping will not include such information)
if (null != typeInfo.TypeId) {
discriminatorMap[typeInfo.TypeId] = columnMap;
}
}
if (allMaps != null) {
allMaps.Add(columnMap);
}
// Finally walk through my subtypes
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
CreateEntityColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps, false);
}
//
// Build up the list of rel property column maps
//
if (handleRelProperties) {
BuildRelPropertyColumnMaps(typeInfo, true);
}
return columnMap;
}
///
/// Build up the list of columnmaps for the relproperties.
/// Assumption: rel-properties follow after ALL the regular properties of the
/// types in the type hierarchy.
/// For now, we're simply going to ignore the rel-property columnmaps - we're
/// just going to use this function to "drain" the corresponding vars
///
/// typeinfo for the entity type
/// should we get rel-properties from our supertype instances
private void BuildRelPropertyColumnMaps(TypeInfo typeInfo, bool includeSupertypeRelProperties) {
//
// Get the appropriate set of rel-properties
//
IEnumerable relProperties = null;
if (includeSupertypeRelProperties) {
relProperties = m_typeInfo.RelPropertyHelper.GetRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase);
}
else {
relProperties = m_typeInfo.RelPropertyHelper.GetDeclaredOnlyRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase);
}
//
// Create a column-map for each rel-properties
//
foreach (RelProperty property in relProperties) {
ColumnMap propertyColumnMap = CreateColumnMap(property.ToEnd.TypeUsage, property.ToString());
}
//
// Add all subtypes
//
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
BuildRelPropertyColumnMaps(subTypeInfo, false);
}
}
///
/// Create a column map for the entitysetid column
///
///
///
private SimpleColumnMap CreateEntitySetIdColumnMap(md.EdmProperty prop) {
return CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(prop), c_EntitySetIdColumnName);
}
///
/// Creates a column map for a polymorphic type. This method first
/// creates column maps for each type that is a subtype of the input type,
/// and then creates a dictionary of typeid value -> column
/// Finally, a PolymorphicColumnMap is created with these pieces of information
///
/// Info about the type
/// column name
///
private SimplePolymorphicColumnMap CreatePolymorphicColumnMap(TypeInfo typeInfo, string name) {
// if the typeInfo has a DiscriminatorMap, use TrailingSpaceComparer to ensure that lookups
// against discriminator values that SQL Server has right-padded (e.g. nchar and char) are properly
// interpreted
Dictionary discriminatorMap = new Dictionary(
typeInfo.RootType.DiscriminatorMap == null ? null : TrailingSpaceComparer.Instance);
// abstract types may not have discriminator values, but may nonetheless be interesting
List allMaps = new List();
// SQLBUDT #433011 -- Polymorphic types must construct column maps
// that map to the entire type hierarchy, so we
// need to use the RootType, not the current type.
TypeInfo rootTypeInfo = typeInfo.RootType;
// Get the type discriminant column first
SimpleColumnMap typeIdColumnMap = CreateTypeIdColumnMap(rootTypeInfo.TypeIdProperty);
// Prepare a place for the constructors to put the columns on the base
// type, as they identify them.
TypedColumnMap rootTypeColumnMap = null;
// process complex/entity types appropriately
// use the same name for the column
if (md.TypeSemantics.IsComplexType(typeInfo.Type)) {
rootTypeColumnMap = CreateComplexTypeColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps);
}
else {
rootTypeColumnMap = CreateEntityColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps, true);
}
// Naturally, nothing is simple; we need to walk the rootTypeColumnMap hierarchy
// and find the column map for the type that we are supposed to have as the base
// type of this hierarchy.
TypedColumnMap baseTypeColumnMap = null;
foreach (TypedColumnMap value in allMaps) {
if (md.TypeSemantics.IsEquivalent(value.Type, typeInfo.Type))
{
baseTypeColumnMap = value;
break;
}
}
PlanCompiler.Assert(null != baseTypeColumnMap, "Didn't find requested type in polymorphic type hierarchy?");
// Create a polymorphic column map
SimplePolymorphicColumnMap result = new SimplePolymorphicColumnMap(typeInfo.Type, name, baseTypeColumnMap.Properties, typeIdColumnMap, discriminatorMap);
return result;
}
///
/// Create a column map for a record type. Simply iterates through the
/// list of fields, and produces a column map for each field
///
/// Type information for the record type
/// column name
///
private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name) {
PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType");
SimpleColumnMap nullSentinelColumnMap = null;
if (typeInfo.HasNullSentinelProperty) {
nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName);
}
md.ReadOnlyMetadataCollection properties = TypeHelpers.GetProperties(typeInfo.Type);
ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count];
for (int i = 0; i < propertyColumnMapList.Length; ++i) {
md.EdmMember property = properties[i];
propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
}
RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap);
return result;
}
///
/// Create a column map for a ref type
///
/// Type information for the ref type
/// Name of the column
/// Column map for the ref type
private RefColumnMap CreateRefColumnMap(TypeInfo typeInfo, string name) {
SimpleColumnMap entitySetIdColumnMap = null;
if (typeInfo.HasEntitySetIdProperty) {
entitySetIdColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.EntitySetIdProperty), c_EntitySetIdColumnName);
}
// get the target entity type,
md.EntityType entityType = (md.EntityType) (TypeHelpers.GetEdmType(typeInfo.Type).ElementType);
// Iterate through the list of "key" properties
SimpleColumnMap[] keyColList = new SimpleColumnMap[entityType.KeyMembers.Count];
for (int i = 0; i < keyColList.Length; ++i) {
md.EdmMember property = entityType.KeyMembers[i];
keyColList[i] = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
}
// Create the entity identity
EntityIdentity identity = CreateEntityIdentity(entityType, entitySetIdColumnMap, keyColList);
RefColumnMap result = new RefColumnMap(typeInfo.Type, name, identity);
return result;
}
///
/// Create a simple columnmap - applies only to scalar properties
/// (Temporarily, also for collections)
/// Simply picks up the next available column in the reader
///
/// Column type
/// column name
/// Column map for this column
private SimpleColumnMap CreateSimpleColumnMap(md.TypeUsage type, string name) {
Var newVar = GetNextVar();
SimpleColumnMap result = new VarRefColumnMap(type, name, newVar);
return result;
}
///
/// Create a column map for the typeid column
///
///
///
private SimpleColumnMap CreateTypeIdColumnMap(md.EdmProperty prop) {
return CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(prop), c_TypeIdColumnName);
}
///
/// Create a column map for a structural column - ref/complextype/entity/record
///
/// Type info for the type
/// column name
///
private ColumnMap CreateStructuralColumnMap(md.TypeUsage type, string name) {
// Get our augmented type information for this type
TypeInfo typeInfo = m_typeInfo.GetTypeInfo(type);
// records?
if (md.TypeSemantics.IsRowType(type)) {
return CreateRecordColumnMap(typeInfo, name);
}
// ref?
if (md.TypeSemantics.IsReferenceType(type)) {
return CreateRefColumnMap(typeInfo, name);
}
// polymorphic type?
if (typeInfo.HasTypeIdProperty) {
return CreatePolymorphicColumnMap(typeInfo, name);
}
// process complex/entity types appropriately
if (md.TypeSemantics.IsComplexType(type)) {
return CreateComplexTypeColumnMap(typeInfo, name, null, null, null);
}
if (md.TypeSemantics.IsEntityType(type)) {
return CreateEntityColumnMap(typeInfo, name, null, null, null, true);
}
// Anything else is not supported (this currently includes relationship types)
throw EntityUtil.NotSupported(type.GetType().ToString());
}
///
/// Build out an EntityIdentity structure - for use by EntityColumnMap and RefColumnMap
///
/// the entity type in question
/// column map for the entitysetid column
/// column maps for the keys
///
private EntityIdentity CreateEntityIdentity(md.EntityType entityType,
SimpleColumnMap entitySetIdColumnMap,
SimpleColumnMap[] keyColumnMaps) {
//
// If we have an entitysetid (and therefore, a column map for the entitysetid),
// then use a discriminated entity identity; otherwise, we use a simpleentityidentity
// instead
//
if (entitySetIdColumnMap != null) {
return new DiscriminatedEntityIdentity(entitySetIdColumnMap, m_typeInfo.EntitySetIdToEntitySetMap, keyColumnMaps);
}
else {
md.EntitySet entitySet = m_typeInfo.GetEntitySet(entityType);
PlanCompiler.Assert(entitySet != null, "Expected non-null entityset when no entitysetid is required. Entity type = " + entityType);
return new SimpleEntityIdentity(entitySet, keyColumnMaps);
}
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....], [....]
//---------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Common.Utils;
using md = System.Data.Metadata.Edm;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
using System.Globalization;
namespace System.Data.Query.PlanCompiler {
internal class ColumnMapProcessor {
#region "public" methods
internal ColumnMap ExpandColumnMap() {
// special handling for the case when the top-level var is a collection.
// The element type of the collection may have changed, and consequently a new
// var will have been created. We simply create a columnmap with that var.
CollectionVarInfo collectionVarInfo = m_varInfo as CollectionVarInfo;
if (collectionVarInfo != null) {
return new VarRefColumnMap(m_columnMap.Var.Type, m_columnMap.Name, collectionVarInfo.NewVar);
}
else {
return this.CreateColumnMap(m_columnMap.Var.Type, m_columnMap.Name);
}
}
#endregion
#region Constructors
internal ColumnMapProcessor(VarRefColumnMap columnMap, VarInfo varInfo, StructuredTypeInfo typeInfo) {
m_columnMap = columnMap;
m_varInfo = varInfo;
PlanCompiler.Assert(varInfo.NewVars != null && varInfo.NewVars.Count > 0, "No new Vars specified");
m_varList = varInfo.NewVars.GetEnumerator();
m_typeInfo = typeInfo;
}
#endregion
#region private state
private IEnumerator m_varList;
private VarInfo m_varInfo;
private VarRefColumnMap m_columnMap;
private StructuredTypeInfo m_typeInfo;
private const string c_TypeIdColumnName = "__TypeId"; // name of the typeid column
private const string c_EntitySetIdColumnName = "__EntitySetId"; // name of the entityset column
private const string c_NullSentinelColumnName = "__NullSentinel"; // name of the nullability column
#endregion
#region private methods
private Var GetNextVar() {
if (m_varList.MoveNext()) {
return m_varList.Current;
}
PlanCompiler.Assert(false, "Could not GetNextVar");
return null;
}
///
/// Creates a column map for a column
///
/// column datatype
/// column name
///
private ColumnMap CreateColumnMap(md.TypeUsage type, string name) {
// For simple types, create a simple column map
// Temporarily, handle collections exactly the same way
if (!TypeUtils.IsStructuredType(type)) {
return CreateSimpleColumnMap(type, name);
}
// At this point, we must be dealing with either a record type, a
// complex type, or an entity type
return CreateStructuralColumnMap(type, name);
}
///
/// Create a column map for a complextype column
///
/// Type information for the type
/// column name
/// Supertype info if any
/// Dictionary of typeidvalue->column map
/// List of all maps
///
private ComplexTypeColumnMap CreateComplexTypeColumnMap(TypeInfo typeInfo, string name, ComplexTypeColumnMap superTypeColumnMap,
Dictionary discriminatorMap, List allMaps) {
List propertyColumnMapList = new List();
IEnumerable myProperties = null;
SimpleColumnMap nullSentinelColumnMap = null;
if (typeInfo.HasNullSentinelProperty) {
nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName);
}
// Copy over information from my supertype if it already exists
if (superTypeColumnMap != null) {
foreach (ColumnMap c in superTypeColumnMap.Properties) {
propertyColumnMapList.Add(c);
}
myProperties = TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type);
}
else {
// need to get all members otherwise
myProperties = TypeHelpers.GetAllStructuralMembers(typeInfo.Type);
}
// Now add on all of my "specific" properties
foreach (md.EdmMember property in myProperties) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
}
// Create a map for myself
ComplexTypeColumnMap columnMap = new ComplexTypeColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), nullSentinelColumnMap);
// if a dictionary is supplied, add myself to the dictionary
if (discriminatorMap != null) {
discriminatorMap[typeInfo.TypeId] = columnMap;
}
if (allMaps != null) {
allMaps.Add(columnMap);
}
// Finally walk through my subtypes - use the same column name
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
CreateComplexTypeColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps);
}
return columnMap;
}
///
/// Create a column map for an entitytype column.
/// Currently, the key columns are not duplicated (ie) they point into the
/// same locations as in the properties list.
/// Note: we also don't handle keys that are properties of nested fields
///
/// Type information for the type
/// column name
/// supertype information if any
/// Dictionary of typeid->column map information
/// List of all column maps (including those without typeid)
/// should we handle rel-properties?
///
private EntityColumnMap CreateEntityColumnMap(TypeInfo typeInfo, string name, EntityColumnMap superTypeColumnMap,
Dictionary discriminatorMap, List allMaps, bool handleRelProperties) {
EntityColumnMap columnMap = null;
List propertyColumnMapList = new List();
// Copy over information from my supertype if it already exists
if (superTypeColumnMap != null) {
// get supertype properties
foreach (ColumnMap c in superTypeColumnMap.Properties) {
propertyColumnMapList.Add(c);
}
// Now add on all of my "specific" properties
foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
}
// create the entity column map w/ information from my supertype
columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), superTypeColumnMap.EntityIdentity);
}
else {
SimpleColumnMap entitySetIdColumnMap = null;
if (typeInfo.HasEntitySetIdProperty) {
entitySetIdColumnMap = CreateEntitySetIdColumnMap(typeInfo.EntitySetIdProperty);
}
// build up a list of key columns
List keyColumnMapList = new List();
// Create a dictionary to look up the key properties
Dictionary keyPropertyMap = new Dictionary();
foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) {
ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
propertyColumnMapList.Add(propertyColumnMap);
// add property to keymap, if this property is part of the key
if (md.TypeSemantics.IsPartOfKey(property)) {
md.EdmProperty edmProperty = property as md.EdmProperty;
PlanCompiler.Assert(edmProperty != null, "EntityType key member is not property?");
keyPropertyMap[edmProperty] = propertyColumnMap;
}
}
// Build up the key list if required
foreach (md.EdmMember keyProperty in TypeHelpers.GetEdmType(typeInfo.Type).KeyMembers) {
md.EdmProperty edmKeyProperty = keyProperty as md.EdmProperty;
PlanCompiler.Assert(edmKeyProperty!=null, "EntityType key member is not property?");
SimpleColumnMap keyColumnMap = keyPropertyMap[edmKeyProperty] as SimpleColumnMap;
PlanCompiler.Assert(keyColumnMap != null, "keyColumnMap is null");
keyColumnMapList.Add(keyColumnMap);
}
//
// Create the entity identity.
//
EntityIdentity identity = CreateEntityIdentity((md.EntityType)typeInfo.Type.EdmType, entitySetIdColumnMap, keyColumnMapList.ToArray());
// finally create the entity column map
columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), identity);
}
// if a dictionary is supplied, add myself to the dictionary (abstract types need not be added)
if (discriminatorMap != null) {
// where DiscriminatedNewInstanceOp is used, there will not be an explicit type id for an abstract type
// or types that do not appear in the QueryView
// (the mapping will not include such information)
if (null != typeInfo.TypeId) {
discriminatorMap[typeInfo.TypeId] = columnMap;
}
}
if (allMaps != null) {
allMaps.Add(columnMap);
}
// Finally walk through my subtypes
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
CreateEntityColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps, false);
}
//
// Build up the list of rel property column maps
//
if (handleRelProperties) {
BuildRelPropertyColumnMaps(typeInfo, true);
}
return columnMap;
}
///
/// Build up the list of columnmaps for the relproperties.
/// Assumption: rel-properties follow after ALL the regular properties of the
/// types in the type hierarchy.
/// For now, we're simply going to ignore the rel-property columnmaps - we're
/// just going to use this function to "drain" the corresponding vars
///
/// typeinfo for the entity type
/// should we get rel-properties from our supertype instances
private void BuildRelPropertyColumnMaps(TypeInfo typeInfo, bool includeSupertypeRelProperties) {
//
// Get the appropriate set of rel-properties
//
IEnumerable relProperties = null;
if (includeSupertypeRelProperties) {
relProperties = m_typeInfo.RelPropertyHelper.GetRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase);
}
else {
relProperties = m_typeInfo.RelPropertyHelper.GetDeclaredOnlyRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase);
}
//
// Create a column-map for each rel-properties
//
foreach (RelProperty property in relProperties) {
ColumnMap propertyColumnMap = CreateColumnMap(property.ToEnd.TypeUsage, property.ToString());
}
//
// Add all subtypes
//
foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes) {
BuildRelPropertyColumnMaps(subTypeInfo, false);
}
}
///
/// Create a column map for the entitysetid column
///
///
///
private SimpleColumnMap CreateEntitySetIdColumnMap(md.EdmProperty prop) {
return CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(prop), c_EntitySetIdColumnName);
}
///
/// Creates a column map for a polymorphic type. This method first
/// creates column maps for each type that is a subtype of the input type,
/// and then creates a dictionary of typeid value -> column
/// Finally, a PolymorphicColumnMap is created with these pieces of information
///
/// Info about the type
/// column name
///
private SimplePolymorphicColumnMap CreatePolymorphicColumnMap(TypeInfo typeInfo, string name) {
// if the typeInfo has a DiscriminatorMap, use TrailingSpaceComparer to ensure that lookups
// against discriminator values that SQL Server has right-padded (e.g. nchar and char) are properly
// interpreted
Dictionary discriminatorMap = new Dictionary(
typeInfo.RootType.DiscriminatorMap == null ? null : TrailingSpaceComparer.Instance);
// abstract types may not have discriminator values, but may nonetheless be interesting
List allMaps = new List();
// SQLBUDT #433011 -- Polymorphic types must construct column maps
// that map to the entire type hierarchy, so we
// need to use the RootType, not the current type.
TypeInfo rootTypeInfo = typeInfo.RootType;
// Get the type discriminant column first
SimpleColumnMap typeIdColumnMap = CreateTypeIdColumnMap(rootTypeInfo.TypeIdProperty);
// Prepare a place for the constructors to put the columns on the base
// type, as they identify them.
TypedColumnMap rootTypeColumnMap = null;
// process complex/entity types appropriately
// use the same name for the column
if (md.TypeSemantics.IsComplexType(typeInfo.Type)) {
rootTypeColumnMap = CreateComplexTypeColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps);
}
else {
rootTypeColumnMap = CreateEntityColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps, true);
}
// Naturally, nothing is simple; we need to walk the rootTypeColumnMap hierarchy
// and find the column map for the type that we are supposed to have as the base
// type of this hierarchy.
TypedColumnMap baseTypeColumnMap = null;
foreach (TypedColumnMap value in allMaps) {
if (md.TypeSemantics.IsEquivalent(value.Type, typeInfo.Type))
{
baseTypeColumnMap = value;
break;
}
}
PlanCompiler.Assert(null != baseTypeColumnMap, "Didn't find requested type in polymorphic type hierarchy?");
// Create a polymorphic column map
SimplePolymorphicColumnMap result = new SimplePolymorphicColumnMap(typeInfo.Type, name, baseTypeColumnMap.Properties, typeIdColumnMap, discriminatorMap);
return result;
}
///
/// Create a column map for a record type. Simply iterates through the
/// list of fields, and produces a column map for each field
///
/// Type information for the record type
/// column name
///
private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name) {
PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType");
SimpleColumnMap nullSentinelColumnMap = null;
if (typeInfo.HasNullSentinelProperty) {
nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName);
}
md.ReadOnlyMetadataCollection properties = TypeHelpers.GetProperties(typeInfo.Type);
ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count];
for (int i = 0; i < propertyColumnMapList.Length; ++i) {
md.EdmMember property = properties[i];
propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
}
RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap);
return result;
}
///
/// Create a column map for a ref type
///
/// Type information for the ref type
/// Name of the column
/// Column map for the ref type
private RefColumnMap CreateRefColumnMap(TypeInfo typeInfo, string name) {
SimpleColumnMap entitySetIdColumnMap = null;
if (typeInfo.HasEntitySetIdProperty) {
entitySetIdColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.EntitySetIdProperty), c_EntitySetIdColumnName);
}
// get the target entity type,
md.EntityType entityType = (md.EntityType) (TypeHelpers.GetEdmType(typeInfo.Type).ElementType);
// Iterate through the list of "key" properties
SimpleColumnMap[] keyColList = new SimpleColumnMap[entityType.KeyMembers.Count];
for (int i = 0; i < keyColList.Length; ++i) {
md.EdmMember property = entityType.KeyMembers[i];
keyColList[i] = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
}
// Create the entity identity
EntityIdentity identity = CreateEntityIdentity(entityType, entitySetIdColumnMap, keyColList);
RefColumnMap result = new RefColumnMap(typeInfo.Type, name, identity);
return result;
}
///
/// Create a simple columnmap - applies only to scalar properties
/// (Temporarily, also for collections)
/// Simply picks up the next available column in the reader
///
/// Column type
/// column name
/// Column map for this column
private SimpleColumnMap CreateSimpleColumnMap(md.TypeUsage type, string name) {
Var newVar = GetNextVar();
SimpleColumnMap result = new VarRefColumnMap(type, name, newVar);
return result;
}
///
/// Create a column map for the typeid column
///
///
///
private SimpleColumnMap CreateTypeIdColumnMap(md.EdmProperty prop) {
return CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(prop), c_TypeIdColumnName);
}
///
/// Create a column map for a structural column - ref/complextype/entity/record
///
/// Type info for the type
/// column name
///
private ColumnMap CreateStructuralColumnMap(md.TypeUsage type, string name) {
// Get our augmented type information for this type
TypeInfo typeInfo = m_typeInfo.GetTypeInfo(type);
// records?
if (md.TypeSemantics.IsRowType(type)) {
return CreateRecordColumnMap(typeInfo, name);
}
// ref?
if (md.TypeSemantics.IsReferenceType(type)) {
return CreateRefColumnMap(typeInfo, name);
}
// polymorphic type?
if (typeInfo.HasTypeIdProperty) {
return CreatePolymorphicColumnMap(typeInfo, name);
}
// process complex/entity types appropriately
if (md.TypeSemantics.IsComplexType(type)) {
return CreateComplexTypeColumnMap(typeInfo, name, null, null, null);
}
if (md.TypeSemantics.IsEntityType(type)) {
return CreateEntityColumnMap(typeInfo, name, null, null, null, true);
}
// Anything else is not supported (this currently includes relationship types)
throw EntityUtil.NotSupported(type.GetType().ToString());
}
///
/// Build out an EntityIdentity structure - for use by EntityColumnMap and RefColumnMap
///
/// the entity type in question
/// column map for the entitysetid column
/// column maps for the keys
///
private EntityIdentity CreateEntityIdentity(md.EntityType entityType,
SimpleColumnMap entitySetIdColumnMap,
SimpleColumnMap[] keyColumnMaps) {
//
// If we have an entitysetid (and therefore, a column map for the entitysetid),
// then use a discriminated entity identity; otherwise, we use a simpleentityidentity
// instead
//
if (entitySetIdColumnMap != null) {
return new DiscriminatedEntityIdentity(entitySetIdColumnMap, m_typeInfo.EntitySetIdToEntitySetMap, keyColumnMaps);
}
else {
md.EntitySet entitySet = m_typeInfo.GetEntitySet(entityType);
PlanCompiler.Assert(entitySet != null, "Expected non-null entityset when no entitysetid is required. Entity type = " + entityType);
return new SimpleEntityIdentity(entitySet, keyColumnMaps);
}
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.