public static void Validate(Parent parent) { // Simulate a validation pass that enumerates all children. foreach (Child child in parent.Children) { foreach (GrandChild grandChild in child.Children) { GreatGrandChild greatGrandChild = grandChild.Child; } } }
public void DeleteParent(Parent parent) { // normally you wouldn't validate a deleted hierarchy, // but we do it here for test validation CompositionHelper.Validate(parent); ((CompositionEntityBase)parent).OperationResult = "Delete"; // Delete all children in the hierarchy. foreach (Child child in parent.Children) { foreach (GrandChild grandChild in child.Children) { GreatGrandChild greatGrandChild = grandChild.Child; if (greatGrandChild != null) { } } } }
public void InsertParent(Parent parent) { // first validate the hierarchy CompositionHelper.Validate(parent); ((CompositionEntityBase)parent).OperationResult = "Insert"; // for a new parent, all children will also be new // so we enumerate all and "add" them foreach (Child child in parent.Children) { ((CompositionEntityBase)child).OperationResult = "Insert"; foreach (GrandChild grandChild in child.Children) { ((CompositionEntityBase)grandChild).OperationResult = "Insert"; GreatGrandChild greatGrandChild = grandChild.Child; if (greatGrandChild != null) { ((CompositionEntityBase)greatGrandChild).OperationResult = "Insert"; } } } }
public void DeleteGreatGrandChild(GreatGrandChild greatGrandChild) { SetOperationInvoked(greatGrandChild); ((CompositionEntityBase)greatGrandChild).OperationResult = "Delete"; }
public void UpdateParent(Parent parent) { // first validate the hierarchy CompositionHelper.Validate(parent); ((CompositionEntityBase)parent).OperationResult = "Update"; // for an updated, children might be added, updated // or deleted. We need to enumerate all and act appropriately foreach (Child child in this.ChangeSet.GetAssociatedChanges(parent, p => p.Children)) { ChangeOperation changeOp = this.ChangeSet.GetChangeOperation(child); if (changeOp == ChangeOperation.Insert) { ((CompositionEntityBase)child).OperationResult = "Insert"; } else if (changeOp == ChangeOperation.Update) { ((CompositionEntityBase)child).OperationResult = "Update"; } else if (changeOp == ChangeOperation.Delete) { ((CompositionEntityBase)child).OperationResult = "Delete"; } // now process child updates for the child foreach (GrandChild grandChild in this.ChangeSet.GetAssociatedChanges(child, p => p.Children)) { changeOp = this.ChangeSet.GetChangeOperation(grandChild); if (changeOp == ChangeOperation.Insert) { ((CompositionEntityBase)grandChild).OperationResult = "Insert"; } else if (changeOp == ChangeOperation.Update) { ((CompositionEntityBase)grandChild).OperationResult = "Update"; } else if (changeOp == ChangeOperation.Delete) { ((CompositionEntityBase)grandChild).OperationResult = "Delete"; } // finally, process any great grand child updates GreatGrandChild updatedGreateGrandChild = this.ChangeSet.GetAssociatedChanges(grandChild, p => p.Child).Cast <GreatGrandChild>().SingleOrDefault(); if (updatedGreateGrandChild != null) { changeOp = this.ChangeSet.GetChangeOperation(updatedGreateGrandChild); if (changeOp == ChangeOperation.Insert) { ((CompositionEntityBase)updatedGreateGrandChild).OperationResult = "Insert"; } else if (changeOp == ChangeOperation.Update) { ((CompositionEntityBase)updatedGreateGrandChild).OperationResult = "Update"; } else if (changeOp == ChangeOperation.Delete) { ((CompositionEntityBase)updatedGreateGrandChild).OperationResult = "Delete"; } } } } }
public void CustomOp_GreatGrandChild(GreatGrandChild greatGrandChild) { this.SetOperationInvoked(greatGrandChild, "CustomOp_GreatGrandChild"); ((CompositionEntityBase)greatGrandChild).OperationResult += ",CustomOp_GreatGrandChild"; }
public void InsertGreatGrandChild(GreatGrandChild greatGrandChild) { SetOperationInvoked(greatGrandChild); ((CompositionEntityBase)greatGrandChild).OperationResult = "Insert"; }
public void DeleteGreatGrandChild(GreatGrandChild greatGrandChild) { SetOperationInvoked(greatGrandChild); ((CompositionEntityBase)greatGrandChild).OperationResult = "Delete"; }
public void HierarchicalChangeTracking_ChildAssociationUpdates_EntityCollection() { CompositionScenarios_Explicit ctxt = new CompositionScenarios_Explicit(CompositionScenarios_Explicit_Uri); Parent parent = CreateCompositionHierarchy(3, 3); ctxt.Parents.Attach(parent); // Remove a child and add one Child c = parent.Children.First(); GrandChild gc = c.Children.ToArray()[1]; GreatGrandChild ggc = gc.Child; gc.Child = null; // remove GrandChild newGc = new GrandChild { ID = 100 }; GreatGrandChild newGgc = new GreatGrandChild { ID = 100 }; c.Children.Add(newGc); // add newGc.Child = newGgc; Assert.IsTrue(parent.HasChanges); Assert.IsTrue(c.HasChanges); Assert.IsTrue(gc.HasChanges); Assert.IsFalse(ggc.HasChanges); Assert.AreEqual(EntityState.Deleted, ggc.EntityState); EntityChangeSet cs = ctxt.EntityContainer.GetChanges(); Assert.IsTrue(cs.AddedEntities.Count == 2 && cs.ModifiedEntities.Count == 3 && cs.RemovedEntities.Count == 1); // Reject the remove and verify state ((IRevertibleChangeTracking)gc).RejectChanges(); Assert.IsTrue(parent.HasChanges); Assert.IsTrue(c.HasChanges); Assert.IsFalse(gc.HasChanges); Assert.IsFalse(ggc.HasChanges); cs = ctxt.EntityContainer.GetChanges(); Assert.IsTrue(cs.AddedEntities.Count == 2 && cs.ModifiedEntities.Count == 2 && cs.RemovedEntities.Count == 0); Assert.AreSame(ggc, gc.Child); ((IRevertibleChangeTracking)c).RejectChanges(); cs = ctxt.EntityContainer.GetChanges(); Assert.IsTrue(cs.AddedEntities.Count == 0 && cs.ModifiedEntities.Count == 0 && cs.RemovedEntities.Count == 0); }
public void CustomOp_GreatGrandChild(GreatGrandChild greatGrandChild) { ((CompositionEntityBase)greatGrandChild).OperationResult += ",CustomOp_GreatGrandChild"; }
public void InsertGreatGrandChild(GreatGrandChild greatGrandChild) { SetOperationInvoked(greatGrandChild); ((CompositionEntityBase)greatGrandChild).OperationResult = "Insert"; }
public void CustomOp_GreatGrandChild(GreatGrandChild greatGrandChild) { ((CompositionEntityBase)greatGrandChild).OperationResult += ",CustomOp_GreatGrandChild"; }
/// <summary> /// Invokes the 'CustomOp_GreatGrandChild' method of the specified <see cref="GreatGrandChild"/> entity. /// </summary> /// <param name="greatGrandChild">The <see cref="GreatGrandChild"/> entity instance.</param> public void CustomOp_GreatGrandChild(GreatGrandChild greatGrandChild) { greatGrandChild.CustomOp_GreatGrandChild(); }
private bool FilterChild(GreatGrandChild entity) { return (entity.ParentID == this.ID); }
/// <summary> /// Make a bunch of multilevel updates to a hierarchy /// </summary> private void HierarchyUpdate(Uri testUri) { CompositionScenarios_Explicit ctxt = new CompositionScenarios_Explicit(testUri); Parent parent = null; SubmitOperation so = null; LoadOperation lo = ctxt.Load(ctxt.GetParentsQuery(), false); IEnumerable<Entity> expectedUpdates = null; EnqueueConditional(() => lo.IsComplete); EnqueueCallback(delegate { TestHelperMethods.AssertOperationSuccess(lo); parent = ctxt.Parents.First(); Child existingChild = parent.Children.First(); Assert.AreSame(parent, ((Entity)existingChild).Parent); GrandChild existingGrandChild = existingChild.Children.Skip(1).Take(1).Single(); // add a few new children Child newChild = new Child { ID = 100 }; parent.Children.Add(newChild); GrandChild newGc = new GrandChild { ID = 100 }; existingChild.Children.Add(newGc); GreatGrandChild newGgc = new GreatGrandChild { ID = 100 }; // update a few children GrandChild updatedGrandChild = existingChild.Children.First(p => p.EntityState != EntityState.New); updatedGrandChild.Property += "x"; // remove a few children GreatGrandChild deletedGreatGrandChild = existingGrandChild.Child; existingGrandChild.Child = null; // invoke a custom method on the parent parent.CustomOp_Parent(); EntityChangeSet cs = ctxt.EntityContainer.GetChanges(); Assert.IsTrue(cs.AddedEntities.Count == 2 && cs.ModifiedEntities.Count == 4 && cs.RemovedEntities.Count == 1); Assert.IsTrue(cs.AddedEntities.Contains(newChild)); Assert.IsTrue(cs.AddedEntities.Contains(newGc)); Assert.IsTrue(cs.ModifiedEntities.Contains(parent)); Assert.IsTrue(cs.ModifiedEntities.Contains(existingChild)); Assert.IsTrue(cs.ModifiedEntities.Contains(existingGrandChild)); Assert.IsTrue(cs.ModifiedEntities.Contains(updatedGrandChild)); Assert.IsTrue(cs.RemovedEntities.Contains(deletedGreatGrandChild)); // direct test verifying that we create the correct set of // ChangeSetEntries to send to the server int modifiedCount = cs.AddedEntities.Count + cs.ModifiedEntities.Count + cs.RemovedEntities.Count; int expectedOperationCount = 24; IEnumerable<ChangeSetEntry> entityOps = ChangeSetBuilder.Build(cs); int entityOpCount = entityOps.Count(); Assert.AreEqual(expectedOperationCount, entityOpCount); Assert.AreEqual(expectedOperationCount - modifiedCount, entityOps.Count(p => p.Operation == EntityOperationType.None)); // verify that original associations are set up correctly this.ValidateEntityOperationAssociations(entityOps); expectedUpdates = cs.Where(p => p.HasChildChanges || p.HasPropertyChanges).ToArray(); so = ctxt.SubmitChanges(TestHelperMethods.DefaultOperationAction, null); }); EnqueueConditional(() => so.IsComplete); EnqueueCallback(delegate { this.VerifySuccess(ctxt, so, expectedUpdates); // verify that the custom method was invoked string[] updateResults = parent.OperationResult.Split(','); Assert.IsTrue(updateResults.Contains("CustomOp_Parent")); }); EnqueueTestComplete(); }
public void Composition_InvalidParentUpdate_EntityRef() { ConfigurableEntityContainer container = new ConfigurableEntityContainer(); container.CreateSet<GrandChild>(EntitySetOperations.All); container.CreateSet<GreatGrandChild>(EntitySetOperations.All); EntitySet<GrandChild> parentSet = container.GetEntitySet<GrandChild>(); EntitySet<GreatGrandChild> childSet = container.GetEntitySet<GreatGrandChild>(); GrandChild parent1 = new GrandChild() { ID = 1 }; GrandChild parent2 = new GrandChild() { ID = 2 }; GreatGrandChild child = new GreatGrandChild() { ID = 1, Parent = parent1 }; parentSet.Attach(parent1); parentSet.Attach(parent2); Assert.IsTrue(childSet.IsAttached(child), "Child was not attached automatically."); Assert.AreSame(parent1, ((Entity)child).Parent, "Entity.Parent doesn't reflect the parent-child relationship."); // point the child to a new parent, which results // in the child being reparented (an invalid update) child.Parent = parent2; EntityChangeSet changeSet = container.GetChanges(); Assert.AreEqual(EntityState.Modified, child.EntityState); Assert.AreEqual(EntityState.Modified, parent1.EntityState); Assert.AreEqual(EntityState.Modified, parent2.EntityState); // Verify that changing the parent throws an exception when // changes are validated ExceptionHelper.ExpectInvalidOperationException(delegate { ChangeSetBuilder.CheckForInvalidUpdates(changeSet); }, string.Format(Resource.Entity_CantReparentComposedChild, child)); }
public void Composition_MultipleRemoveReadds() { ConfigurableEntityContainer container = new ConfigurableEntityContainer(); container.CreateSet<Parent>(EntitySetOperations.All); container.CreateSet<Child>(EntitySetOperations.All); container.CreateSet<GrandChild>(EntitySetOperations.All); container.CreateSet<GreatGrandChild>(EntitySetOperations.All); EntitySet<Parent> parentSet = container.GetEntitySet<Parent>(); EntitySet<Child> childSet = container.GetEntitySet<Child>(); EntitySet<GreatGrandChild> ggChildSet = container.GetEntitySet<GreatGrandChild>(); Parent parent = new Parent() { ID = 1 }; Child child = new Child() { ID = 1, Parent = parent }; container.LoadEntities(new Entity[] { parent, child }); parent.Children.Remove(child); Assert.AreEqual(EntityState.Deleted, child.EntityState); Assert.IsFalse(childSet.Contains(child)); parent.Children.Add(child); Assert.AreEqual(EntityState.Modified, child.EntityState); Assert.IsTrue(childSet.Contains(child)); parent.Children.Remove(child); Assert.AreEqual(EntityState.Deleted, child.EntityState); Assert.IsFalse(childSet.Contains(child)); // verify the same scenario for a singleton composition GrandChild gc = new GrandChild { ID = 1 }; GreatGrandChild ggc = new GreatGrandChild { ID = 1, ParentID = 1 }; container.LoadEntities(new Entity[] { gc, ggc }); Assert.AreSame(ggc, gc.Child); gc.Child = null; Assert.AreEqual(EntityState.Deleted, ggc.EntityState); Assert.IsFalse(ggChildSet.Contains(ggc)); gc.Child = ggc; Assert.AreEqual(EntityState.Unmodified, ggc.EntityState); Assert.IsTrue(ggChildSet.Contains(ggc)); gc.Child = null; Assert.AreEqual(EntityState.Deleted, ggc.EntityState); Assert.IsFalse(ggChildSet.Contains(ggc)); }
public void CustomOp_GreatGrandChild(GreatGrandChild greatGrandChild) { this.SetOperationInvoked(greatGrandChild, "CustomOp_GreatGrandChild"); ((CompositionEntityBase)greatGrandChild).OperationResult += ",CustomOp_GreatGrandChild"; }
public void Changeset_GetAssociatedChanges_Singleton() { DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(CompositionScenarios_Explicit)); // verify singleton change of None GreatGrandChild unmodifiedGgc = new GreatGrandChild(); GrandChild currGrandChild = new GrandChild { Child = unmodifiedGgc }; GrandChild origGrandChild = new GrandChild { Child = unmodifiedGgc }; ChangeSetEntry gcOperation = new ChangeSetEntry(1, currGrandChild, origGrandChild, DomainOperation.Update); gcOperation.Associations = new Dictionary<string, int[]> { { "Child", new int[] { 2 } } }; ChangeSetEntry ggcOperation = new ChangeSetEntry(2, unmodifiedGgc, null, DomainOperation.None); ChangeSet cs = new ChangeSet(new ChangeSetEntry[] { gcOperation, ggcOperation }); GreatGrandChild ggcChange = cs.GetAssociatedChanges(currGrandChild, p => p.Child, ChangeOperation.None).Cast<GreatGrandChild>().SingleOrDefault(); Assert.AreSame(unmodifiedGgc, ggcChange); // verify singleton insert GreatGrandChild newGgc = new GreatGrandChild(); currGrandChild = new GrandChild { Child = newGgc }; origGrandChild = new GrandChild { Child = null }; gcOperation = new ChangeSetEntry(1, currGrandChild, origGrandChild, DomainOperation.Update); gcOperation.Associations = new Dictionary<string, int[]> { { "Child", new int[] { 2 } } }; ggcOperation = new ChangeSetEntry(2, newGgc, null, DomainOperation.Insert); cs = new ChangeSet(new ChangeSetEntry[] { gcOperation, ggcOperation }); ggcChange = cs.GetAssociatedChanges(currGrandChild, p => p.Child, ChangeOperation.Insert).Cast<GreatGrandChild>().SingleOrDefault(); Assert.AreSame(newGgc, ggcChange); Assert.AreEqual(ChangeOperation.Insert, cs.GetChangeOperation(newGgc)); // verify singleton update GreatGrandChild modifiedGgc = new GreatGrandChild(); currGrandChild = new GrandChild { Child = modifiedGgc }; origGrandChild = new GrandChild { Child = modifiedGgc }; gcOperation = new ChangeSetEntry(1, currGrandChild, origGrandChild, DomainOperation.Update); gcOperation.Associations = new Dictionary<string, int[]> { { "Child", new int[] { 2 } } }; ggcOperation = new ChangeSetEntry(2, modifiedGgc, unmodifiedGgc, DomainOperation.Update); cs = new ChangeSet(new ChangeSetEntry[] { gcOperation, ggcOperation }); ggcChange = cs.GetAssociatedChanges(currGrandChild, p => p.Child, ChangeOperation.Update).Cast<GreatGrandChild>().SingleOrDefault(); Assert.AreSame(modifiedGgc, ggcChange); Assert.AreSame(unmodifiedGgc, cs.GetOriginal(modifiedGgc)); Assert.AreEqual(ChangeOperation.Update, cs.GetChangeOperation(modifiedGgc)); // verify singleton delete GreatGrandChild deletedGgc = new GreatGrandChild(); currGrandChild = new GrandChild { Child = null }; origGrandChild = new GrandChild { Child = deletedGgc }; gcOperation = new ChangeSetEntry(1, currGrandChild, null, DomainOperation.Update); gcOperation.OriginalAssociations = new Dictionary<string, int[]>() { { "Child", new int[] { 2 } } }; ggcOperation = new ChangeSetEntry(2, deletedGgc, null, DomainOperation.Delete); gcOperation.OriginalAssociations = new Dictionary<string, int[]>() { { "Child", new int[] { 2 } } }; cs = new ChangeSet(new ChangeSetEntry[] { gcOperation, ggcOperation }); ggcChange = cs.GetAssociatedChanges(currGrandChild, p => p.Child, ChangeOperation.Delete).Cast<GreatGrandChild>().SingleOrDefault(); Assert.AreSame(deletedGgc, ggcChange); Assert.AreSame(null, cs.GetOriginal(deletedGgc)); Assert.AreEqual(ChangeOperation.Delete, cs.GetChangeOperation(deletedGgc)); }