Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / DynamicData / DynamicData / MetaForeignKeyColumn.cs / 1305376 / MetaForeignKeyColumn.cs
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Security.Permissions;
using System.Web.DynamicData.ModelProviders;
using System.Linq;
using System.Web.UI;
namespace System.Web.DynamicData {
///
/// A special column representing many-1 relationships
///
public class MetaForeignKeyColumn : MetaColumn, IMetaForeignKeyColumn {
// Maps a foreign key name to the name that should be used in a Linq expression for filtering
// i.e. the foreignkey name might be surfaced through a custom type descriptor e.g. CategoryID but we might really want to use
// Category.CategoryId in the expression
private Dictionary _foreignKeyFilterMapping;
public MetaForeignKeyColumn(MetaTable table, ColumnProvider entityMember)
: base(table, entityMember) {
}
///
/// Perform initialization logic for this column
///
internal protected override void Initialize() {
base.Initialize();
ParentTable = Model.GetTable(Provider.Association.ToTable.Name, Table.DataContextType);
CreateForeignKeyFilterMapping(ForeignKeyNames, ParentTable.PrimaryKeyNames, (foreignKey) => Table.EntityType.GetProperty(foreignKey) != null);
}
internal void CreateForeignKeyFilterMapping(IList foreignKeyNames, IList primaryKeyNames, Func propertyExists) {
// HACK: Some tests don't mock foreign key names, but this should never be the case at runtime
if (foreignKeyNames == null) {
return;
}
int pKIndex = 0;
foreach (string fkName in foreignKeyNames) {
if (!propertyExists(fkName)) {
if (_foreignKeyFilterMapping == null) {
_foreignKeyFilterMapping = new Dictionary();
}
_foreignKeyFilterMapping[fkName] = Name + "." + primaryKeyNames[pKIndex];
}
pKIndex++;
}
}
///
/// The parent table of the relationship (e.g. Categories in Products->Categories)
///
public MetaTable ParentTable {
get;
// internal for unit testing
internal set;
}
///
/// Returns true if this foriegn key column is part of the primary key of its table
/// e.g. Order and Product are PKs in the Order_Details table
///
public bool IsPrimaryKeyInThisTable {
get {
return Provider.Association.IsPrimaryKeyInThisTable;
}
}
///
/// This is used when saving the value of a foreign key, e.g. when selected from a drop down.
///
public void ExtractForeignKey(IDictionary dictionary, string value) {
if (String.IsNullOrEmpty(value)) {
// If the value is null, set all the FKs to null
foreach (string fkName in ForeignKeyNames) {
dictionary[fkName] = null;
}
}
else {
string[] fkValues = Misc.ParseCommaSeparatedString(value);
Debug.Assert(fkValues.Length == ForeignKeyNames.Count);
for (int i = 0; i < fkValues.Length; i++) {
dictionary[ForeignKeyNames[i]] = fkValues[i];
}
}
}
///
/// Return the value of all the foreign keys components for the passed in row
///
public IList GetForeignKeyValues(object row) {
object[] values = new object[ForeignKeyNames.Count];
int index = 0;
bool hasNonNullKey = false;
foreach (string fkMemberName in ForeignKeyNames) {
object keyValue = Table.Provider.EvaluateForeignKey(row, fkMemberName);
// Set a flag if at least one non-null key is found
if (keyValue != null)
hasNonNullKey = true;
values[index++] = keyValue;
}
// If all the foreign keys are null, return null
if (!hasNonNullKey)
return null;
return values;
}
///
/// Get a comma separated list of values representing the foreign key
///
///
///
public string GetForeignKeyString(object row) {
// Don't do anything if the row is null
if (row == null) {
return String.Empty;
}
return Misc.PersistListToCommaSeparatedString(GetForeignKeyValues(row));
}
///
/// Override allowing for sorting by the display column of the parent table (e.g. in the Products table, the Category column
/// will be sorted by the Category.Name column order)
///
internal override string SortExpressionInternal {
get {
var displayColumn = ParentTable.DisplayColumn;
var sortExpression = Provider.Association.GetSortExpression(displayColumn.Provider);
return sortExpression ?? String.Empty;
}
}
/*protected*/ internal override bool ScaffoldNoCache {
get {
// always display many-1 associations
return true;
}
}
public string GetFilterExpression(string foreignKeyName) {
string mappedforeignKey;
// If the mapping doesn't exists for this property then we return the actual FK
if (_foreignKeyFilterMapping == null || !_foreignKeyFilterMapping.TryGetValue(foreignKeyName, out mappedforeignKey)) {
return foreignKeyName;
}
return mappedforeignKey;
}
///
/// Shortcut for getting the path to the details action for the given row
///
///
///
public string GetForeignKeyDetailsPath(object row) {
return GetForeignKeyPath(PageAction.Details, row);
}
public string GetForeignKeyPath(string action, object row) {
return GetForeignKeyPath(action, row, null);
}
public string GetForeignKeyPath(string action, object row, string path) {
// If there is no row, we can't get a path
if (row == null)
return String.Empty;
// Get the value of all the FKs
IList fkValues = GetForeignKeyValues(row);
// If null, there is no associated object to go to
if (fkValues == null)
return String.Empty;
return GetForeignKeyMetaTable(row).GetActionPath(action, fkValues, path);
}
internal MetaTable GetForeignKeyMetaTable(object row) {
// Get the foreign key reference
object foreignKeyReference = DataBinder.GetPropertyValue(row, Name);
// if the type is different to the parent table type then proceed to get the correct table
if (foreignKeyReference != null) {
// Get the correct MetaTable based on the live object. This is used for inheritance scenarios where the type of the navigation
// property's parent table is some base type but the instance is pointing to a derived type.
Type rowType = foreignKeyReference.GetType();
MetaTable rowTable = Misc.GetTableFromTypeHierarchy(rowType);
if (rowTable != null) {
return rowTable;
}
}
return ParentTable;
}
///
/// The names of the underlying foreign keys that make up this association
///
public ReadOnlyCollection ForeignKeyNames { get { return Provider.Association.ForeignKeyNames; } }
IMetaTable IMetaForeignKeyColumn.ParentTable {
get {
return ParentTable;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Security.Permissions;
using System.Web.DynamicData.ModelProviders;
using System.Linq;
using System.Web.UI;
namespace System.Web.DynamicData {
///
/// A special column representing many-1 relationships
///
public class MetaForeignKeyColumn : MetaColumn, IMetaForeignKeyColumn {
// Maps a foreign key name to the name that should be used in a Linq expression for filtering
// i.e. the foreignkey name might be surfaced through a custom type descriptor e.g. CategoryID but we might really want to use
// Category.CategoryId in the expression
private Dictionary _foreignKeyFilterMapping;
public MetaForeignKeyColumn(MetaTable table, ColumnProvider entityMember)
: base(table, entityMember) {
}
///
/// Perform initialization logic for this column
///
internal protected override void Initialize() {
base.Initialize();
ParentTable = Model.GetTable(Provider.Association.ToTable.Name, Table.DataContextType);
CreateForeignKeyFilterMapping(ForeignKeyNames, ParentTable.PrimaryKeyNames, (foreignKey) => Table.EntityType.GetProperty(foreignKey) != null);
}
internal void CreateForeignKeyFilterMapping(IList foreignKeyNames, IList primaryKeyNames, Func propertyExists) {
// HACK: Some tests don't mock foreign key names, but this should never be the case at runtime
if (foreignKeyNames == null) {
return;
}
int pKIndex = 0;
foreach (string fkName in foreignKeyNames) {
if (!propertyExists(fkName)) {
if (_foreignKeyFilterMapping == null) {
_foreignKeyFilterMapping = new Dictionary();
}
_foreignKeyFilterMapping[fkName] = Name + "." + primaryKeyNames[pKIndex];
}
pKIndex++;
}
}
///
/// The parent table of the relationship (e.g. Categories in Products->Categories)
///
public MetaTable ParentTable {
get;
// internal for unit testing
internal set;
}
///
/// Returns true if this foriegn key column is part of the primary key of its table
/// e.g. Order and Product are PKs in the Order_Details table
///
public bool IsPrimaryKeyInThisTable {
get {
return Provider.Association.IsPrimaryKeyInThisTable;
}
}
///
/// This is used when saving the value of a foreign key, e.g. when selected from a drop down.
///
public void ExtractForeignKey(IDictionary dictionary, string value) {
if (String.IsNullOrEmpty(value)) {
// If the value is null, set all the FKs to null
foreach (string fkName in ForeignKeyNames) {
dictionary[fkName] = null;
}
}
else {
string[] fkValues = Misc.ParseCommaSeparatedString(value);
Debug.Assert(fkValues.Length == ForeignKeyNames.Count);
for (int i = 0; i < fkValues.Length; i++) {
dictionary[ForeignKeyNames[i]] = fkValues[i];
}
}
}
///
/// Return the value of all the foreign keys components for the passed in row
///
public IList GetForeignKeyValues(object row) {
object[] values = new object[ForeignKeyNames.Count];
int index = 0;
bool hasNonNullKey = false;
foreach (string fkMemberName in ForeignKeyNames) {
object keyValue = Table.Provider.EvaluateForeignKey(row, fkMemberName);
// Set a flag if at least one non-null key is found
if (keyValue != null)
hasNonNullKey = true;
values[index++] = keyValue;
}
// If all the foreign keys are null, return null
if (!hasNonNullKey)
return null;
return values;
}
///
/// Get a comma separated list of values representing the foreign key
///
///
///
public string GetForeignKeyString(object row) {
// Don't do anything if the row is null
if (row == null) {
return String.Empty;
}
return Misc.PersistListToCommaSeparatedString(GetForeignKeyValues(row));
}
///
/// Override allowing for sorting by the display column of the parent table (e.g. in the Products table, the Category column
/// will be sorted by the Category.Name column order)
///
internal override string SortExpressionInternal {
get {
var displayColumn = ParentTable.DisplayColumn;
var sortExpression = Provider.Association.GetSortExpression(displayColumn.Provider);
return sortExpression ?? String.Empty;
}
}
/*protected*/ internal override bool ScaffoldNoCache {
get {
// always display many-1 associations
return true;
}
}
public string GetFilterExpression(string foreignKeyName) {
string mappedforeignKey;
// If the mapping doesn't exists for this property then we return the actual FK
if (_foreignKeyFilterMapping == null || !_foreignKeyFilterMapping.TryGetValue(foreignKeyName, out mappedforeignKey)) {
return foreignKeyName;
}
return mappedforeignKey;
}
///
/// Shortcut for getting the path to the details action for the given row
///
///
///
public string GetForeignKeyDetailsPath(object row) {
return GetForeignKeyPath(PageAction.Details, row);
}
public string GetForeignKeyPath(string action, object row) {
return GetForeignKeyPath(action, row, null);
}
public string GetForeignKeyPath(string action, object row, string path) {
// If there is no row, we can't get a path
if (row == null)
return String.Empty;
// Get the value of all the FKs
IList fkValues = GetForeignKeyValues(row);
// If null, there is no associated object to go to
if (fkValues == null)
return String.Empty;
return GetForeignKeyMetaTable(row).GetActionPath(action, fkValues, path);
}
internal MetaTable GetForeignKeyMetaTable(object row) {
// Get the foreign key reference
object foreignKeyReference = DataBinder.GetPropertyValue(row, Name);
// if the type is different to the parent table type then proceed to get the correct table
if (foreignKeyReference != null) {
// Get the correct MetaTable based on the live object. This is used for inheritance scenarios where the type of the navigation
// property's parent table is some base type but the instance is pointing to a derived type.
Type rowType = foreignKeyReference.GetType();
MetaTable rowTable = Misc.GetTableFromTypeHierarchy(rowType);
if (rowTable != null) {
return rowTable;
}
}
return ParentTable;
}
///
/// The names of the underlying foreign keys that make up this association
///
public ReadOnlyCollection ForeignKeyNames { get { return Provider.Association.ForeignKeyNames; } }
IMetaTable IMetaForeignKeyColumn.ParentTable {
get {
return ParentTable;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.