public IEnumerable<Model> RemoveBranch (Model model) { Node node; if (!nodes.TryGetValue (model, out node)) return Enumerable.Empty<Model> (); var removedModels = new List<Model> (); // Find elders (highest parents): var elders = new HashSet<Model> (); var parentStack = new Stack<Model> (); parentStack.Push (model); while (parentStack.Count > 0) { var parent = parentStack.Pop (); var parentNode = nodes [parent]; if (parentNode.Parents.Count == 0) { elders.Add (parent); } else { foreach (var grandparent in parentNode.Parents) { parentStack.Push (grandparent); } } } // Remove elders from graph: foreach (var elder in elders) { Remove (elder, removedModels); } return removedModels; }
public virtual void Merge (Model model) { if (model.GetType () != GetType ()) throw new ArgumentException ("Cannot merge models of different kind", "model"); lock (SyncRoot) { MergeSimpleOverwrite (model); } }
public IEnumerable<Model> Remove (Model model) { Node node; if (!nodes.TryGetValue (model, out node)) return Enumerable.Empty<Model> (); var removedModels = new List<Model> (); Remove (model, removedModels); return removedModels; }
public void Add (Model model, Model parent = null) { if (parent != null) Add (parent); Node node; if (!nodes.TryGetValue (model, out node)) { nodes [model] = node = new Node (); } if (parent != null) { node.Parents.Add (parent); nodes [parent].Children.Add (model); } }
private void Remove (Model model, List<Model> deleted) { Node node; if (!nodes.TryGetValue (model, out node)) return; // Remove children foreach (var child in node.Children.ToList ()) { Remove (child, deleted); } // Detach from parents foreach (var parent in node.Parents.ToList ()) { nodes [parent].Children.Remove (model); } nodes.Remove (model); deleted.Add (model); }
protected void MergeSimpleOverwrite (Model other) { if (this.IsShared && other.IsShared) throw new InvalidOperationException ("Cannot merge two shared models."); IsMerging = true; try { // Very simple merging rules: the newest one is always correct, remote deletion overrides everything. if (other.ModifiedAt <= this.ModifiedAt && other.RemoteDeletedAt == null) return; // Update properties defined in subclasses: var props = from p in GetType ().GetProperties () where p.CanRead && p.CanWrite && p.DeclaringType != typeof(Model) select p; foreach (var prop in props) { var val = prop.GetValue (other, null); prop.SetValue (this, val, null); } // Update our own properties in a specific order: this.RemoteId = other.RemoteId; this.RemoteDeletedAt = other.RemoteDeletedAt; this.RemoteRejected = other.RemoteRejected; if (other.RemoteDeletedAt != null) { // Custom logic for handling remote deletions: this.IsPersisted = false; this.DeletedAt = other.RemoteDeletedAt.Value; } else { if (other.IsPersisted) this.IsPersisted = other.IsPersisted; this.DeletedAt = other.DeletedAt; } this.ModifiedAt = other.ModifiedAt; this.IsDirty = other.IsDirty; } finally { IsMerging = false; } }
public ModelChangedMessage (Model model, string property) : base (model) { this.propertyName = property; }