/// <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);
        }
Esempio n. 2
0
        /// <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));
            }
        }