2016-08-03 10:59:49 +00:00
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// <copyright file="EntityDataSourceWrapper.cs" company="Microsoft">
|
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
// </copyright>
|
|
|
|
|
//
|
2017-08-21 15:34:15 +00:00
|
|
|
|
// @owner Microsoft
|
|
|
|
|
// @backupOwner Microsoft
|
2016-08-03 10:59:49 +00:00
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
using System;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Configuration;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Data.Common;
|
|
|
|
|
using System.Data.Metadata.Edm;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Data.Objects;
|
|
|
|
|
using System.Data.Objects.DataClasses;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Web.UI;
|
|
|
|
|
|
|
|
|
|
namespace System.Web.UI.WebControls
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wraps an entity displayed in the data source in an ICustomTypeDescriptor
|
|
|
|
|
/// implementation that flattens complex types and exposes references.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal class EntityDataSourceWrapper : ICustomTypeDescriptor
|
|
|
|
|
{
|
|
|
|
|
private readonly EntityDataSourceWrapperCollection _collection;
|
|
|
|
|
private readonly ObjectStateEntry _stateEntry;
|
|
|
|
|
|
|
|
|
|
internal EntityDataSourceWrapper(EntityDataSourceWrapperCollection collection, object trackedEntity)
|
|
|
|
|
{
|
|
|
|
|
EntityDataSourceUtil.CheckArgumentNull(collection, "collection");
|
|
|
|
|
EntityDataSourceUtil.CheckArgumentNull(trackedEntity, "trackedEntity");
|
|
|
|
|
|
|
|
|
|
this._collection = collection;
|
|
|
|
|
|
|
|
|
|
// retrieve state entry
|
|
|
|
|
if (!this._collection.Context.ObjectStateManager.TryGetObjectStateEntry(trackedEntity, out _stateEntry))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException(Strings.ComponentNotFromProperCollection, "trackedEntity");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets entity wrapped by this type descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal object WrappedEntity
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return this._stateEntry.Entity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal RelationshipManager RelationshipManager
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return this._stateEntry.RelationshipManager;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets collection containing this wrapper.
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal EntityDataSourceWrapperCollection Collection
|
|
|
|
|
{
|
|
|
|
|
get { return this._collection; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region ICustomTypeDescriptor Implementation
|
|
|
|
|
System.ComponentModel.AttributeCollection System.ComponentModel.ICustomTypeDescriptor.GetAttributes() { return new System.ComponentModel.AttributeCollection(); }
|
|
|
|
|
string ICustomTypeDescriptor.GetClassName() { return null; }
|
|
|
|
|
string ICustomTypeDescriptor.GetComponentName() { return null; }
|
|
|
|
|
TypeConverter ICustomTypeDescriptor.GetConverter() { return null; }
|
|
|
|
|
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return null; }
|
|
|
|
|
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { return null; }
|
|
|
|
|
object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return null; }
|
|
|
|
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { return null; }
|
|
|
|
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { return null; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public PropertyDescriptorCollection GetProperties()
|
|
|
|
|
{
|
|
|
|
|
return ((ITypedList)this._collection).GetItemProperties(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
|
|
|
|
|
{
|
|
|
|
|
return ((ICustomTypeDescriptor)this).GetProperties();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
|
|
|
|
|
{
|
|
|
|
|
return this.WrappedEntity;
|
|
|
|
|
}
|
|
|
|
|
#endregion ICustomTypeDescriptor Implementation
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Use this method to set the properties on the wrapped entity
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="propertiesFromViewState"></param>
|
|
|
|
|
/// <param name="wrapper"></param>
|
|
|
|
|
/// <param name="overwriteSameValue"></param>
|
|
|
|
|
internal void SetAllProperties(Dictionary<string, object> propertiesFromViewState, bool overwriteSameValue,
|
|
|
|
|
ref Dictionary<string, Exception> propertySettingExceptionsCaught)
|
|
|
|
|
{
|
|
|
|
|
// We aggregate the reference descriptors rather than setting them directly
|
|
|
|
|
// to account for compound keys (we need all components of the key to create
|
|
|
|
|
// an EntityKey that can be set on the EntityReference)
|
|
|
|
|
var referenceList = new List<KeyValuePair<EntityDataSourceReferenceKeyColumn, object>>();
|
|
|
|
|
|
|
|
|
|
foreach (EntityDataSourceWrapperPropertyDescriptor descriptor in _collection.AllPropertyDescriptors)
|
|
|
|
|
{
|
|
|
|
|
// figure out which display name to match for this descriptor
|
|
|
|
|
string displayName = descriptor.Column.DisplayName;
|
|
|
|
|
|
|
|
|
|
// if we have a controlling column, use its display name instead
|
|
|
|
|
if (descriptor.Column.ControllingColumn != null)
|
|
|
|
|
{
|
|
|
|
|
displayName = descriptor.Column.ControllingColumn.DisplayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object value;
|
|
|
|
|
if (propertiesFromViewState.TryGetValue(displayName, out value))
|
|
|
|
|
{
|
|
|
|
|
// get all changed ReferencePropertyDescriptor from ViewState
|
|
|
|
|
EntityDataSourceReferenceKeyColumn referenceColumn = descriptor.Column as EntityDataSourceReferenceKeyColumn;
|
|
|
|
|
|
|
|
|
|
// convert the value as needed
|
|
|
|
|
object adjustedValue = EntityDataSourceUtil.ConvertType(value, descriptor.PropertyType, descriptor.DisplayName);
|
|
|
|
|
|
|
|
|
|
if (null != referenceColumn)
|
|
|
|
|
{
|
|
|
|
|
referenceList.Add(new KeyValuePair<EntityDataSourceReferenceKeyColumn, object>(
|
|
|
|
|
referenceColumn, adjustedValue));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (overwriteSameValue || adjustedValue != descriptor.GetValue(this))
|
|
|
|
|
{
|
|
|
|
|
if (EntityDataSourceUtil.NullCanBeAssignedTo(descriptor.PropertyType) || null != adjustedValue)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
descriptor.SetValue(this, adjustedValue);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
// The property descriptor uses reflection to set the property. Therefore, the inner exception contains the actual message.
|
|
|
|
|
Exception exceptionToThrow = e;
|
|
|
|
|
if (e.InnerException != null)
|
|
|
|
|
{
|
|
|
|
|
exceptionToThrow = e.InnerException;
|
|
|
|
|
}
|
|
|
|
|
if (null == propertySettingExceptionsCaught)
|
|
|
|
|
{
|
|
|
|
|
propertySettingExceptionsCaught = new Dictionary<string, Exception>();
|
|
|
|
|
}
|
|
|
|
|
propertySettingExceptionsCaught.Add(descriptor.DisplayName, exceptionToThrow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// aggregate setting for EntityKey
|
|
|
|
|
SetEntityKeyProperties(referenceList, overwriteSameValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetEntityKeyProperties(
|
|
|
|
|
List<KeyValuePair<EntityDataSourceReferenceKeyColumn, object>> referenceList, bool overwriteSameValue)
|
|
|
|
|
{
|
|
|
|
|
EntityDataSourceUtil.CheckArgumentNull(referenceList, "referenceList");
|
|
|
|
|
|
|
|
|
|
var groups = referenceList.GroupBy(r => r.Key.Group);
|
|
|
|
|
|
|
|
|
|
foreach (var group in groups)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object> partialKeys = new Dictionary<string, object>();
|
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<EntityDataSourceReferenceKeyColumn, object> reference in group)
|
|
|
|
|
{
|
|
|
|
|
// convert the value as needed
|
|
|
|
|
EntityDataSourceReferenceKeyColumn column = reference.Key;
|
|
|
|
|
object keyValue = reference.Value;
|
|
|
|
|
|
|
|
|
|
if (null == keyValue)
|
|
|
|
|
{
|
|
|
|
|
partialKeys = null;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
partialKeys.Add(column.KeyMember.Name, keyValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we only set the entitykey for once, although there might be more than one
|
|
|
|
|
// properties descriptor associated with the same entitykey
|
|
|
|
|
group.Key.SetKeyValues(this, partialKeys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|