1 //---------------------------------------------------------------------
2 // <copyright file="EntityDataSourceWrapper.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
11 using System.Configuration;
12 using System.ComponentModel;
13 using System.Data.Common;
14 using System.Data.Metadata.Edm;
15 using System.Reflection;
16 using System.Data.Objects;
17 using System.Data.Objects.DataClasses;
18 using System.Collections.Generic;
19 using System.Diagnostics;
21 using System.Collections.ObjectModel;
25 namespace System.Web.UI.WebControls
28 /// Wraps an entity displayed in the data source in an ICustomTypeDescriptor
29 /// implementation that flattens complex types and exposes references.
31 internal class EntityDataSourceWrapper : ICustomTypeDescriptor
33 private readonly EntityDataSourceWrapperCollection _collection;
34 private readonly ObjectStateEntry _stateEntry;
36 internal EntityDataSourceWrapper(EntityDataSourceWrapperCollection collection, object trackedEntity)
38 EntityDataSourceUtil.CheckArgumentNull(collection, "collection");
39 EntityDataSourceUtil.CheckArgumentNull(trackedEntity, "trackedEntity");
41 this._collection = collection;
43 // retrieve state entry
44 if (!this._collection.Context.ObjectStateManager.TryGetObjectStateEntry(trackedEntity, out _stateEntry))
46 throw new ArgumentException(Strings.ComponentNotFromProperCollection, "trackedEntity");
51 /// Gets entity wrapped by this type descriptor.
53 internal object WrappedEntity
57 return this._stateEntry.Entity;
61 internal RelationshipManager RelationshipManager
65 return this._stateEntry.RelationshipManager;
70 /// Gets collection containing this wrapper.
72 internal EntityDataSourceWrapperCollection Collection
74 get { return this._collection; }
77 #region ICustomTypeDescriptor Implementation
78 System.ComponentModel.AttributeCollection System.ComponentModel.ICustomTypeDescriptor.GetAttributes() { return new System.ComponentModel.AttributeCollection(); }
79 string ICustomTypeDescriptor.GetClassName() { return null; }
80 string ICustomTypeDescriptor.GetComponentName() { return null; }
81 TypeConverter ICustomTypeDescriptor.GetConverter() { return null; }
82 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return null; }
83 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { return null; }
84 object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return null; }
85 EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { return null; }
86 EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { return null; }
89 public PropertyDescriptorCollection GetProperties()
91 return ((ITypedList)this._collection).GetItemProperties(null);
94 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
96 return ((ICustomTypeDescriptor)this).GetProperties();
99 object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
101 return this.WrappedEntity;
103 #endregion ICustomTypeDescriptor Implementation
106 /// Use this method to set the properties on the wrapped entity
108 /// <param name="propertiesFromViewState"></param>
109 /// <param name="wrapper"></param>
110 /// <param name="overwriteSameValue"></param>
111 internal void SetAllProperties(Dictionary<string, object> propertiesFromViewState, bool overwriteSameValue,
112 ref Dictionary<string, Exception> propertySettingExceptionsCaught)
114 // We aggregate the reference descriptors rather than setting them directly
115 // to account for compound keys (we need all components of the key to create
116 // an EntityKey that can be set on the EntityReference)
117 var referenceList = new List<KeyValuePair<EntityDataSourceReferenceKeyColumn, object>>();
119 foreach (EntityDataSourceWrapperPropertyDescriptor descriptor in _collection.AllPropertyDescriptors)
121 // figure out which display name to match for this descriptor
122 string displayName = descriptor.Column.DisplayName;
124 // if we have a controlling column, use its display name instead
125 if (descriptor.Column.ControllingColumn != null)
127 displayName = descriptor.Column.ControllingColumn.DisplayName;
131 if (propertiesFromViewState.TryGetValue(displayName, out value))
133 // get all changed ReferencePropertyDescriptor from ViewState
134 EntityDataSourceReferenceKeyColumn referenceColumn = descriptor.Column as EntityDataSourceReferenceKeyColumn;
136 // convert the value as needed
137 object adjustedValue = EntityDataSourceUtil.ConvertType(value, descriptor.PropertyType, descriptor.DisplayName);
139 if (null != referenceColumn)
141 referenceList.Add(new KeyValuePair<EntityDataSourceReferenceKeyColumn, object>(
142 referenceColumn, adjustedValue));
146 if (overwriteSameValue || adjustedValue != descriptor.GetValue(this))
148 if (EntityDataSourceUtil.NullCanBeAssignedTo(descriptor.PropertyType) || null != adjustedValue)
152 descriptor.SetValue(this, adjustedValue);
156 // The property descriptor uses reflection to set the property. Therefore, the inner exception contains the actual message.
157 Exception exceptionToThrow = e;
158 if (e.InnerException != null)
160 exceptionToThrow = e.InnerException;
162 if (null == propertySettingExceptionsCaught)
164 propertySettingExceptionsCaught = new Dictionary<string, Exception>();
166 propertySettingExceptionsCaught.Add(descriptor.DisplayName, exceptionToThrow);
173 // aggregate setting for EntityKey
174 SetEntityKeyProperties(referenceList, overwriteSameValue);
177 private void SetEntityKeyProperties(
178 List<KeyValuePair<EntityDataSourceReferenceKeyColumn, object>> referenceList, bool overwriteSameValue)
180 EntityDataSourceUtil.CheckArgumentNull(referenceList, "referenceList");
182 var groups = referenceList.GroupBy(r => r.Key.Group);
184 foreach (var group in groups)
186 Dictionary<string, object> partialKeys = new Dictionary<string, object>();
188 foreach (KeyValuePair<EntityDataSourceReferenceKeyColumn, object> reference in group)
190 // convert the value as needed
191 EntityDataSourceReferenceKeyColumn column = reference.Key;
192 object keyValue = reference.Value;
194 if (null == keyValue)
200 partialKeys.Add(column.KeyMember.Name, keyValue);
203 // we only set the entitykey for once, although there might be more than one
204 // properties descriptor associated with the same entitykey
205 group.Key.SetKeyValues(this, partialKeys);