//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Metadata.Edm;
using System.Data.Common.Utils;
using System.Xml;
using System.Collections.ObjectModel;
using System.Diagnostics;
namespace System.Data.Mapping
{
internal abstract class FunctionImportStructuralTypeMapping
{
internal readonly LineInfo LineInfo;
internal readonly Collection ColumnsRenameList;
internal FunctionImportStructuralTypeMapping(Collection columnsRenameList, LineInfo lineInfo)
{
this.ColumnsRenameList = columnsRenameList;
this.LineInfo = lineInfo;
}
}
internal sealed class FunctionImportEntityTypeMapping : FunctionImportStructuralTypeMapping
{
internal FunctionImportEntityTypeMapping(IEnumerable isOfTypeEntityTypes,
IEnumerable entityTypes, IEnumerable conditions,
Collection columnsRenameList,
LineInfo lineInfo)
: base(columnsRenameList, lineInfo)
{
this.IsOfTypeEntityTypes = new ReadOnlyCollection(
EntityUtil.CheckArgumentNull(isOfTypeEntityTypes, "isOfTypeEntityTypes").ToList());
this.EntityTypes = new ReadOnlyCollection(
EntityUtil.CheckArgumentNull(entityTypes, "entityTypes").ToList());
this.Conditions = new ReadOnlyCollection(
EntityUtil.CheckArgumentNull(conditions, "conditions").ToList());
}
internal readonly ReadOnlyCollection Conditions;
internal readonly ReadOnlyCollection EntityTypes;
internal readonly ReadOnlyCollection IsOfTypeEntityTypes;
///
/// Gets all (concrete) entity types implied by this type mapping.
///
internal IEnumerable GetMappedEntityTypes(ItemCollection itemCollection)
{
const bool includeAbstractTypes = false;
return this.EntityTypes.Concat(
this.IsOfTypeEntityTypes.SelectMany(entityType =>
MetadataHelper.GetTypeAndSubtypesOf(entityType, itemCollection, includeAbstractTypes)
.Cast()));
}
internal IEnumerable GetDiscriminatorColumns()
{
return this.Conditions.Select(condition => condition.ColumnName);
}
}
internal sealed class FunctionImportComplexTypeMapping : FunctionImportStructuralTypeMapping
{
internal readonly ComplexType ReturnType;
internal FunctionImportComplexTypeMapping(ComplexType returnType, Collection columnsRenameList, LineInfo lineInfo)
: base(columnsRenameList, lineInfo)
{
this.ReturnType = returnType;
}
}
internal abstract class FunctionImportReturnTypePropertyMapping
{
internal readonly string CMember;
internal readonly string SColumn;
internal readonly LineInfo LineInfo;
internal FunctionImportReturnTypePropertyMapping(string cMember, string sColumn, LineInfo lineInfo)
{
this.CMember = cMember;
this.SColumn = sColumn;
this.LineInfo = lineInfo;
}
}
internal sealed class FunctionImportReturnTypeScalarPropertyMapping : FunctionImportReturnTypePropertyMapping
{
internal FunctionImportReturnTypeScalarPropertyMapping(string cMember, string sColumn, LineInfo lineInfo)
: base(cMember, sColumn, lineInfo)
{
}
}
///
/// extract the column rename info from polymorphic entity type mappings
///
internal sealed class FunctionImportReturnTypeEntityTypeColumnsRenameBuilder
{
///
/// CMember -> SMember*
///
internal Dictionary ColumnRenameMapping;
internal FunctionImportReturnTypeEntityTypeColumnsRenameBuilder(
Dictionary> isOfTypeEntityTypeColumnsRenameMapping,
Dictionary> entityTypeColumnsRenameMapping)
{
EntityUtil.CheckArgumentNull(isOfTypeEntityTypeColumnsRenameMapping, "isOfTypeEntityTypeColumnsRenameMapping");
EntityUtil.CheckArgumentNull(entityTypeColumnsRenameMapping, "entityTypeColumnsRenameMapping");
this.ColumnRenameMapping = new Dictionary();
// Assign the columns renameMapping to the result dictionary.
foreach (EntityType entityType in isOfTypeEntityTypeColumnsRenameMapping.Keys)
{
this.SetStructuralTypeColumnsRename(
entityType, isOfTypeEntityTypeColumnsRenameMapping[entityType], true/*isTypeOf*/);
}
foreach (EntityType entityType in entityTypeColumnsRenameMapping.Keys)
{
this.SetStructuralTypeColumnsRename(
entityType, entityTypeColumnsRenameMapping[entityType], false/*isTypeOf*/);
}
}
///
/// Set the column mappings for each defaultMemberName.
///
private void SetStructuralTypeColumnsRename(
EntityType entityType,
Collection columnsRenameMapping,
bool isTypeOf)
{
EntityUtil.CheckArgumentNull(entityType, "entityType");
EntityUtil.CheckArgumentNull(columnsRenameMapping, "columnsRenameMapping");
foreach (var mapping in columnsRenameMapping)
{
if (!this.ColumnRenameMapping.Keys.Contains(mapping.CMember))
{
this.ColumnRenameMapping[mapping.CMember] = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(mapping.CMember);
}
this.ColumnRenameMapping[mapping.CMember].AddRename(new FunctionImportReturnTypeStructuralTypeColumn(mapping.SColumn, entityType, isTypeOf, mapping.LineInfo));
}
}
}
internal sealed class FunctionImportReturnTypeStructuralTypeColumn
{
internal readonly StructuralType Type;
internal readonly bool IsTypeOf;
internal readonly string ColumnName;
internal readonly LineInfo LineInfo;
internal FunctionImportReturnTypeStructuralTypeColumn(string columnName, StructuralType type, bool isTypeOf, LineInfo lineInfo)
{
this.ColumnName = columnName;
this.IsTypeOf = isTypeOf;
this.Type = type;
this.LineInfo = lineInfo;
}
}
internal class FunctionImportReturnTypeStructuralTypeColumnRenameMapping
{
private Collection _columnListForType;
private Collection _columnListForIsTypeOfType;
///
/// Null if default mapping is not allowed.
///
private readonly string _defaultMemberName;
private Memoizer _renameCache;
internal FunctionImportReturnTypeStructuralTypeColumnRenameMapping(string defaultMemberName)
{
this._defaultMemberName = defaultMemberName;
this._columnListForType = new Collection();
this._columnListForIsTypeOfType = new Collection();
this._renameCache = new Memoizer(
this.GetRename, EqualityComparer.Default);
}
///
/// for more info.
///
internal string GetRename(EdmType type)
{
IXmlLineInfo lineInfo;
return GetRename(type, out lineInfo);
}
///
/// A default mapping (property "Foo" maps by convention to column "Foo"), if allowed, has the lowest precedence.
/// A mapping for a specific type (EntityType="Bar") takes precedence over a mapping for a hierarchy (EntityType="IsTypeOf(Bar)"))
/// If there are two hierarchy mappings, the most specific mapping takes precedence.
/// For instance, given the types Base, Derived1 : Base, and Derived2 : Derived1,
/// w.r.t. Derived1 "IsTypeOf(Derived1)" takes precedence over "IsTypeOf(Base)" when you ask for the rename of Derived1
///
/// Empty for default rename mapping.
internal string GetRename(EdmType type, out IXmlLineInfo lineInfo)
{
Debug.Assert(type is StructuralType, "we can only rename structural type");
EntityUtil.CheckArgumentNull(type, "type");
var rename = this._renameCache.Evaluate(type as StructuralType);
lineInfo = rename.LineInfo;
return rename.ColumnName;
}
private FunctionImportReturnTypeStructuralTypeColumn GetRename(StructuralType typeForRename)
{
FunctionImportReturnTypeStructuralTypeColumn ofTypecolumn = _columnListForType.FirstOrDefault(t => t.Type == typeForRename);
if (null != ofTypecolumn)
{
return ofTypecolumn;
}
// if there are duplicate istypeof mapping defined rename for the same column, the last one wins
FunctionImportReturnTypeStructuralTypeColumn isOfTypeColumn = _columnListForIsTypeOfType.Where(t => t.Type == typeForRename).LastOrDefault();
if (null != isOfTypeColumn)
{
return isOfTypeColumn;
}
else
{
// find out all the tyes that is isparent type of this lookup type
IEnumerable nodesInBaseHierachy =
_columnListForIsTypeOfType.Where(t => t.Type.IsAssignableFrom(typeForRename));
if (nodesInBaseHierachy.Count() == 0)
{
// non of its parent is renamed, so it will take the default one
return new FunctionImportReturnTypeStructuralTypeColumn(this._defaultMemberName, typeForRename, false, null);
}
else
{
// we will guarantee that there will be some mapping for us on this column
// find out which one is lowest on the link
return GetLowestParentInHierachy(nodesInBaseHierachy);
}
}
}
private FunctionImportReturnTypeStructuralTypeColumn GetLowestParentInHierachy(IEnumerable nodesInHierachy)
{
FunctionImportReturnTypeStructuralTypeColumn lowestParent = null;
foreach (var node in nodesInHierachy)
{
if (lowestParent == null)
{
lowestParent = node;
}
else if (lowestParent.Type.IsAssignableFrom(node.Type))
{
lowestParent = node;
}
}
Debug.Assert(null != lowestParent, "We should have the lowest parent");
return lowestParent;
}
internal void AddRename(FunctionImportReturnTypeStructuralTypeColumn renamedColumn)
{
EntityUtil.CheckArgumentNull(renamedColumn, "renamedColumn");
if (!renamedColumn.IsTypeOf)
{
// add to collection if the mapping is for specific type
this._columnListForType.Add(renamedColumn);
}
else
{
_columnListForIsTypeOfType.Add(renamedColumn);
}
}
}
}