/// <summary> /// Gets the value of the property on the object, instantiating it with a default /// value if it is currently null. /// </summary> private object getValue(object model, PropertyInfo containerProperty) { var value = containerProperty.GetValue(model, null); if (value == null) { value = HistoryHelpers.Instantiate(containerProperty.PropertyType); containerProperty.SetValue(model, value, null); } return(value); }
/// <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)); } }