/// <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 reference = db.GetReferenceForObject(model); return(db.ObjectChanges .Where(o => o.TypeName == typeName) .Where(o => o.ObjectReference == reference) .SelectMany(o => o.PropertyChanges) .Where(p => p.PropertyName == propertyName) .OrderByDescending(p => p.ObjectChange.ChangeSet.Timestamp) .AsEnumerable() .Select(p => new Change <TValue, TPrincipal>(bind <TValue>(p.Value), p.ObjectChange.ChangeSet.Author, p.ObjectChange.ChangeSet.Timestamp))); }
/// <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)); } }
protected virtual bool equalCollectionItems(object a, object b) { return((db.ObjectHasReference(a)) ? (db.GetReferenceForObject(a) == db.GetReferenceForObject(b)) : Equals(a, b)); }