private void applyToProperty(object model, PropertyInfo property, IBindManager binder, string prefix, string remainder) { // If (after taking the prefix into account) this is a complex property change // Recurse, using the object referred to by the first part of the property name // as the new model to apply the change to. if (split(remainder).Count() > 1) { var value = getValue(model, property); applyTo(value, binder, property.PropertyType, ExpressionHelper.Join(prefix, property.Name)); } // Otherwise, if we are now at a simple property change, just bind the value // and set the appropriate property else { var existingValue = property.GetValue(model, null); var value = binder.Bind(wrapped.Value, property.PropertyType, existingValue); if (isEntityCollection(property) && existingValue != null) { // do nothing, its contents were already updated by the binder, // and it's an error to use the property setter for an entity collection } else { property.SetValue(model, value, null); } } }
public object Bind(string raw, Type type, object existingValue) { if (raw == null) { return(null); } return(bindManager.Bind(raw, underlyingType(type), existingValue)); }
protected virtual void fillCollection <ItemType>(ICollection <ItemType> collection, string raw) { foreach (var reference in raw.Split(new char[] { ',' }).Where(r => !string.IsNullOrEmpty(r))) { var item = bindManager.Bind <ItemType>(reference); if (collection.All(i => !equalCollectionItems(i, item))) { collection.Add(item); } } }
/// <summary> /// Retrieve the values that a single property has gone through, most recent /// first (descending date order). /// </summary> public virtual IEnumerable<IChange<TValue, TPrincipal>> ChangesTo<TModel, TValue>(TModel model, Expression<Func<TModel, TValue>> property) { string typeName = typeof(TModel).Name; string propertyName = property.GetPropertyName(); string propertyPrefix = propertyName + "."; string reference = historyContext.GetReferenceForObject(model); var propertyFunc = property.Compile(); var objectChanges = changesTo(model) .SelectMany(o => o.PropertyChanges) .Where(p => p.PropertyName == propertyName || p.PropertyName.StartsWith(propertyPrefix)) .AsEnumerable() .GroupBy(p => p.ObjectChange) .Select(g => new FilteredObjectChange<TPrincipal>(g.Key, g)); // If the propert expression refers to a complex type then we will not have any changes // directly to that property. Instead we will see changes to sub-properties. // We retrieve the history differently for complex types, so here we distinguish which // case we are in by looking at the first change. var sample = objectChanges.SelectMany(o => o.PropertyChanges).FirstOrDefault(); if (sample != null && sample.PropertyName.StartsWith(propertyPrefix)) { // Construct a "seed" instance of the complex type, and then apply changes to it in order // to reconstruct the intermediate states. return applyChangesTo(HistoryHelpers.Instantiate<TValue>(), objectChanges, propertyName) .OrderByDescending(c => c.Timestamp); } else { // Just directly bind the simple property values return objectChanges .OrderByDescending(o => o.ChangeSet.Timestamp) .SelectMany(o => o.PropertyChanges) .Select(p => Change.FromObjectChange(binder.Bind<TValue>(p.Value), p.ObjectChange)); } }