public void InferredAddThenAttach_EntityCollection() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); // track changes on products int productAdded = 0; int productRemoved = 0; int productPropertyChanged = 0; int productsCollectionChanged = 0; EntitySet <Product> productsSet = ec.GetEntitySet <Product>(); productsSet.EntityAdded += (obj, args) => productAdded += 1; productsSet.EntityRemoved += (obj, args) => productRemoved += 1; productsSet.PropertyChanged += (obj, args) => productPropertyChanged += 1; ((INotifyCollectionChanged)productsSet).CollectionChanged += (obj, args) => productsCollectionChanged += 1; // create and add order to container Order order = new Order { OrderID = 1 }; ec.LoadEntities(new Entity[] { order }); ((IChangeTracking)ec).AcceptChanges(); // build a detached graph of a detail and product Order_Detail detail = new Order_Detail { OrderID = 1, ProductID = 2 }; Product product = new Product { ProductID = 3 }; detail.Product = product; // Add detached detail to attached order. // Product is now tracked since it is an 'inferred' entity order.Order_Details.Add(detail); Assert.IsTrue(product.IsInferred); Assert.AreEqual(1, productAdded); Assert.AreEqual(0, productRemoved); Assert.AreEqual(2, productPropertyChanged); Assert.AreEqual(1, productsCollectionChanged); // now explicitly attach product productsSet.Attach(product); // should not have duplicate refernce to product Assert.AreEqual(1, productsSet.Count); // should not raise events since product was already added Assert.AreEqual(1, productAdded); Assert.AreEqual(0, productRemoved); Assert.AreEqual(2, productPropertyChanged); Assert.AreEqual(1, productsCollectionChanged); }
public void IdentityCacheCleanup() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); ec.LoadEntities(new Entity[] { new Product { ProductID = 1 }, new Product { ProductID = 2 }, new Product { ProductID = 3 } }); EntitySet <Product> productSet = ec.GetEntitySet <Product>(); // Delete an entity Product prod = productSet.First(); int key = prod.ProductID; productSet.Remove(prod); ((IChangeTracking)ec).AcceptChanges(); // After the delete, the entity is moved back into the default state Assert.AreEqual(EntityState.Detached, prod.EntityState); // After it has been deleted, we should be able to add // a new entity with the same key Product newProduct = new Product { ProductID = key }; productSet.Add(newProduct); Assert.AreEqual(EntityState.New, newProduct.EntityState); ((IChangeTracking)ec).AcceptChanges(); Product requeriedProduct = productSet.Single(p => p.ProductID == key); Assert.AreSame(newProduct, requeriedProduct); // make sure instances are same // Bug 526544 repro case - delete and submit, then attempt // to re-add prod = productSet.First(); key = prod.ProductID; productSet.Remove(prod); ((IChangeTracking)ec).AcceptChanges(); productSet.Add(prod); Assert.AreEqual(EntityState.New, prod.EntityState); ((IChangeTracking)ec).AcceptChanges(); // verify that when an entity is Detached, it is removed from ID cache // after the detach, attaching an entity with the same key should succeed prod = productSet.First(); key = prod.ProductID; productSet.Detach(prod); newProduct = new Product { ProductID = key }; productSet.Attach(newProduct); requeriedProduct = productSet.Single(p => p.ProductID == key); Assert.AreSame(newProduct, requeriedProduct); // make sure instances are same }
public void InferredAdd_EntityRefs() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); // add a few existing entities Order order1 = new Order { OrderID = 1 }; Order_Detail detail1 = new Order_Detail { OrderID = 2, ProductID = 1 }; ec.LoadEntities(new Entity[] { order1, detail1 }); ((IChangeTracking)ec).AcceptChanges(); Assert.IsFalse(ec.HasChanges); // build a detached graph of a new category and 2 products Category newCategory = new Category { CategoryID = 1 }; Product newProduct1 = new Product { ProductID = 3 }; Product newProduct2 = new Product { ProductID = 4 }; newCategory.Products.Add(newProduct1); newCategory.Products.Add(newProduct2); // set the the Product reference on the existing detail to // one of the new detached products - we expect the entire // graph to be infer added EntityChangeSet cs = ec.GetChanges(); Assert.IsTrue(cs.IsEmpty); detail1.Product = newProduct1; cs = ec.GetChanges(); Assert.AreEqual(3, cs.AddedEntities.Count); Assert.IsTrue(cs.AddedEntities.Contains(newProduct1)); // the entity set directly Assert.IsTrue(cs.AddedEntities.Contains(newCategory)); // inferred via Product.Category ER Assert.IsTrue(cs.AddedEntities.Contains(newProduct2)); // inferred via Category.Products EC // verify that inferred Adds can be state transitioned via subsequent // calls to Attach ec.GetEntitySet <Product>().Attach(newProduct2); newProduct2.ProductName += "x"; cs = ec.GetChanges(); Assert.AreEqual(2, cs.AddedEntities.Count); Assert.AreEqual(2, cs.ModifiedEntities.Count); Assert.IsFalse(cs.AddedEntities.Contains(newProduct2)); Assert.IsTrue(cs.ModifiedEntities.Contains(newProduct2)); }
public void TestAssociations_UpdatedReferencingNew() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); Product p1 = new Product { ProductID = 1, CategoryID = 1 }; Product p2 = new Product { ProductID = 2, CategoryID = 2 }; Category c1 = new Category { CategoryID = 1 }; Category c2 = new Category { CategoryID = 2 }; ec.LoadEntities(new Entity[] { p1, p2, c1, c2 }); // take two existing parents (the FK side of the association) // access their existing children Category prevCat = p1.Category; Assert.IsNotNull(prevCat); prevCat = p2.Category; Assert.IsNotNull(prevCat); // create two new children Category newCat1 = new Category { CategoryID = 3 }; Category newCat2 = new Category { CategoryID = 4 }; // assign the two new children p1.Category = newCat1; p2.Category = newCat2; EntityChangeSet cs = ec.GetChanges(); Assert.AreEqual(2, cs.AddedEntities.Count); Assert.AreEqual(2, cs.ModifiedEntities.Count); List <ChangeSetEntry> entries = ChangeSetBuilder.Build(cs); ChangeSetEntry entry = entries.Single(p => p.Entity == p1); // the bug was that we weren't populating the association map in this // scenario since previously we required BOTH parent and child to be new. // We've relaxed that to ensure that if the child is new, the association // shows up in the map. Assert.IsNotNull(entry.Associations); int[] ids = entry.Associations["Category"]; Category referenced = (Category)entries.Single(p => p.Id == ids.Single()).Entity; Assert.AreSame(newCat1, referenced); }
public void ChangeSet_DontLoadUnloadedAssociations() { NorthwindEntityContainer entities = new NorthwindEntityContainer(); EntitySet <Order> orders = entities.GetEntitySet <Order>(); EntitySet <Order_Detail> details = entities.GetEntitySet <Order_Detail>(); // add a few existing entities Order order = new Order { OrderID = 1 }; Order_Detail detail = new Order_Detail { OrderID = 1, ProductID = 1 }; entities.LoadEntities(new Entity[] { order, detail }); // modify both entities order.Freight = 5; detail.Quantity = 5; IEntityRef er = detail.GetEntityRef("Order"); Assert.IsNull(er); IEntityCollection ec = order.Order_Details; Assert.IsFalse(ec.HasValues); EntityChangeSet cs = entities.GetChanges(); Assert.AreEqual(2, cs.ModifiedEntities.Count); // after computing the changeset, no association members // should have been loaded er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); // after building the operation list, no association members // should have been loaded ChangeSetBuilder.Build(cs); er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); }
public void ChangeSet_DontLoadUnloadedAssociations() { NorthwindEntityContainer entities = new NorthwindEntityContainer(); EntitySet<Order> orders = entities.GetEntitySet<Order>(); EntitySet<Order_Detail> details = entities.GetEntitySet<Order_Detail>(); // add a few existing entities Order order = new Order { OrderID = 1 }; Order_Detail detail = new Order_Detail { OrderID = 1, ProductID = 1 }; entities.LoadEntities(new Entity[] { order, detail }); // modify both entities order.Freight = 5; detail.Quantity = 5; IEntityRef er = detail.GetEntityRef("Order"); Assert.IsNull(er); IEntityCollection ec = order.Order_Details; Assert.IsFalse(ec.HasValues); EntityChangeSet cs = entities.GetChanges(); Assert.AreEqual(2, cs.ModifiedEntities.Count); // after computing the changeset, no association members // should have been loaded er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); // after building the operation list, no association members // should have been loaded ChangeSetBuilder.Build(cs); er = detail.GetEntityRef("Order"); Assert.IsNull(er); Assert.IsFalse(ec.HasValues); }
public void TestAssociations_UpdatedReferencingNew() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); Product p1 = new Product { ProductID = 1, CategoryID = 1 }; Product p2 = new Product { ProductID = 2, CategoryID = 2 }; Category c1 = new Category { CategoryID = 1 }; Category c2 = new Category { CategoryID = 2 }; ec.LoadEntities(new Entity[] { p1, p2, c1, c2 }); // take two existing parents (the FK side of the association) // access their existing children Category prevCat = p1.Category; Assert.IsNotNull(prevCat); prevCat = p2.Category; Assert.IsNotNull(prevCat); // create two new children Category newCat1 = new Category { CategoryID = 3 }; Category newCat2 = new Category { CategoryID = 4 }; // assign the two new children p1.Category = newCat1; p2.Category = newCat2; EntityChangeSet cs = ec.GetChanges(); Assert.AreEqual(2, cs.AddedEntities.Count); Assert.AreEqual(2, cs.ModifiedEntities.Count); List<ChangeSetEntry> entries = ChangeSetBuilder.Build(cs); ChangeSetEntry entry = entries.Single(p => p.Entity == p1); // the bug was that we weren't populating the association map in this // scenario since previously we required BOTH parent and child to be new. // We've relaxed that to ensure that if the child is new, the association // shows up in the map. Assert.IsNotNull(entry.Associations); int[] ids = entry.Associations["Category"]; Category referenced = (Category)entries.Single(p => p.Id == ids.Single()).Entity; Assert.AreSame(newCat1, referenced); }
public void TestAssociations_GraphDelete() { NorthwindEntityContainer entities = new NorthwindEntityContainer(); #region Create a test graph Customer cust = new Customer { CustomerID = "ALFKI" }; Order order = new Order { OrderID = 1 }; order.Customer = cust; order.Order_Details.Add(new Order_Detail { ProductID = 1 }); order.Order_Details.Add(new Order_Detail { ProductID = 2 }); order.Order_Details.Add(new Order_Detail { ProductID = 3 }); entities.LoadEntities(new Entity[] { cust, order }); entities.LoadEntities(order.Order_Details); ((IRevertibleChangeTracking)entities).AcceptChanges(); #endregion // now delete the graph // TODO : currently this has to be done in this specific order // with association modifications being done while the parent // is attached (before it is removed from set) foreach (Order_Detail detail in order.Order_Details) { order.Order_Details.Remove(detail); entities.GetEntitySet<Order_Detail>().Remove(detail); } cust.Orders.Remove(order); entities.GetEntitySet<Order>().Remove(order); entities.GetEntitySet<Customer>().Remove(cust); // verify the changeset EntityChangeSet changeSet = entities.GetChanges(); Assert.AreEqual(5, changeSet.RemovedEntities.Count); // build the operation list and verify it List<ChangeSetEntry> operations = ChangeSetBuilder.Build(changeSet); // verify that the association collections for the Order operation are null ChangeSetEntry orderOperation = operations.Single(p => p.Entity == order); ChangeSetEntry custOperation = operations.Single(p => p.Entity == cust); Assert.IsNull(orderOperation.Associations); Assert.IsNull(orderOperation.OriginalAssociations); Assert.IsNotNull(orderOperation.OriginalEntity); // verify that the association collections for the Customer operation are null Assert.IsNull(custOperation.OriginalEntity); Assert.IsNull(custOperation.Associations); Assert.IsNull(custOperation.OriginalAssociations); // verify that deleted OrderDetails have null associations as well ChangeSetEntry detailOperation = operations.First(p => p.Entity.GetType() == typeof(Order_Detail)); Assert.IsNotNull(detailOperation.OriginalEntity); Assert.IsNull(detailOperation.Associations); Assert.IsNull(detailOperation.OriginalAssociations); }
public void IdentityCacheCleanup() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); ec.LoadEntities(new Entity[] { new Product { ProductID = 1 }, new Product { ProductID = 2 }, new Product { ProductID = 3 } }); EntitySet<Product> productSet = ec.GetEntitySet<Product>(); // Delete an entity Product prod = productSet.First(); int key = prod.ProductID; productSet.Remove(prod); ((IChangeTracking)ec).AcceptChanges(); // After the delete, the entity is moved back into the default state Assert.AreEqual(EntityState.Detached, prod.EntityState); // After it has been deleted, we should be able to add // a new entity with the same key Product newProduct = new Product { ProductID = key }; productSet.Add(newProduct); Assert.AreEqual(EntityState.New, newProduct.EntityState); ((IChangeTracking)ec).AcceptChanges(); Product requeriedProduct = productSet.Single(p => p.ProductID == key); Assert.AreSame(newProduct, requeriedProduct); // make sure instances are same // Bug 526544 repro case - delete and submit, then attempt // to re-add prod = productSet.First(); key = prod.ProductID; productSet.Remove(prod); ((IChangeTracking)ec).AcceptChanges(); productSet.Add(prod); Assert.AreEqual(EntityState.New, prod.EntityState); ((IChangeTracking)ec).AcceptChanges(); // verify that when an entity is Detached, it is removed from ID cache // after the detach, attaching an entity with the same key should succeed prod = productSet.First(); key = prod.ProductID; productSet.Detach(prod); newProduct = new Product { ProductID = key }; productSet.Attach(newProduct); requeriedProduct = productSet.Single(p => p.ProductID == key); Assert.AreSame(newProduct, requeriedProduct); // make sure instances are same }
public void InferredAdd_EntityRefs() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); // add a few existing entities Order order1 = new Order { OrderID = 1 }; Order_Detail detail1 = new Order_Detail { OrderID = 2, ProductID = 1 }; ec.LoadEntities(new Entity[] { order1, detail1 }); ((IChangeTracking)ec).AcceptChanges(); Assert.IsFalse(ec.HasChanges); // build a detached graph of a new category and 2 products Category newCategory = new Category { CategoryID = 1 }; Product newProduct1 = new Product { ProductID = 3 }; Product newProduct2 = new Product { ProductID = 4 }; newCategory.Products.Add(newProduct1); newCategory.Products.Add(newProduct2); // set the the Product reference on the existing detail to // one of the new detached products - we expect the entire // graph to be infer added EntityChangeSet cs = ec.GetChanges(); Assert.IsTrue(cs.IsEmpty); detail1.Product = newProduct1; cs = ec.GetChanges(); Assert.AreEqual(3, cs.AddedEntities.Count); Assert.IsTrue(cs.AddedEntities.Contains(newProduct1)); // the entity set directly Assert.IsTrue(cs.AddedEntities.Contains(newCategory)); // inferred via Product.Category ER Assert.IsTrue(cs.AddedEntities.Contains(newProduct2)); // inferred via Category.Products EC // verify that inferred Adds can be state transitioned via subsequent // calls to Attach ec.GetEntitySet<Product>().Attach(newProduct2); newProduct2.ProductName += "x"; cs = ec.GetChanges(); Assert.AreEqual(2, cs.AddedEntities.Count); Assert.AreEqual(2, cs.ModifiedEntities.Count); Assert.IsFalse(cs.AddedEntities.Contains(newProduct2)); Assert.IsTrue(cs.ModifiedEntities.Contains(newProduct2)); }
public void InferredAdd_EntityCollection() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); // add a few existing entities Order order1 = new Order { OrderID = 1 }; Order order2 = new Order { OrderID = 2 }; Order_Detail detail1 = new Order_Detail { OrderID = 2, ProductID = 1 }; ec.LoadEntities(new Entity[] { order1, order2, detail1 }); ((IChangeTracking)ec).AcceptChanges(); Assert.IsFalse(ec.HasChanges); // build a detached graph of a new category and 2 products, // referenced by a detail Order_Detail newDetail1 = new Order_Detail { OrderID = 1, ProductID = 2 }; Category newCategory = new Category { CategoryID = 1 }; Product newProduct1 = new Product { ProductID = 3 }; Product newProduct2 = new Product { ProductID = 4 }; newCategory.Products.Add(newProduct1); newCategory.Products.Add(newProduct2); newDetail1.Product = newProduct1; EntityChangeSet cs = ec.GetChanges(); Assert.IsTrue(cs.IsEmpty); // verify that adding an unattached entity to an EC results in // the expected inferred Adds order1.Order_Details.Add(newDetail1); cs = ec.GetChanges(); Assert.AreEqual(4, cs.AddedEntities.Count); Assert.IsTrue(cs.AddedEntities.Contains(newDetail1)); // the entity added directly Assert.IsTrue(cs.AddedEntities.Contains(newProduct1)); // inferred via Detail.Product ER Assert.IsTrue(cs.AddedEntities.Contains(newCategory)); // inferred via Product.Category ER Assert.IsTrue(cs.AddedEntities.Contains(newProduct2)); // inferred via Category.Products EC // verify that inferred Adds can be state transitioned via subsequent // calls to Attach ec.GetEntitySet<Product>().Attach(newProduct2); newProduct2.ProductName += "x"; cs = ec.GetChanges(); Assert.AreEqual(3, cs.AddedEntities.Count); Assert.AreEqual(1, cs.ModifiedEntities.Count); Assert.IsFalse(cs.AddedEntities.Contains(newProduct2)); Assert.IsTrue(cs.ModifiedEntities.Contains(newProduct2)); }
public void TestAssociations_GraphDelete() { NorthwindEntityContainer entities = new NorthwindEntityContainer(); #region Create a test graph Customer cust = new Customer { CustomerID = "ALFKI" }; Order order = new Order { OrderID = 1 }; order.Customer = cust; order.Order_Details.Add(new Order_Detail { ProductID = 1 }); order.Order_Details.Add(new Order_Detail { ProductID = 2 }); order.Order_Details.Add(new Order_Detail { ProductID = 3 }); entities.LoadEntities(new Entity[] { cust, order }); entities.LoadEntities(order.Order_Details); ((IRevertibleChangeTracking)entities).AcceptChanges(); #endregion // now delete the graph // TODO : currently this has to be done in this specific order // with association modifications being done while the parent // is attached (before it is removed from set) foreach (Order_Detail detail in order.Order_Details) { order.Order_Details.Remove(detail); entities.GetEntitySet <Order_Detail>().Remove(detail); } cust.Orders.Remove(order); entities.GetEntitySet <Order>().Remove(order); entities.GetEntitySet <Customer>().Remove(cust); // verify the changeset EntityChangeSet changeSet = entities.GetChanges(); Assert.AreEqual(5, changeSet.RemovedEntities.Count); // build the operation list and verify it List <ChangeSetEntry> operations = ChangeSetBuilder.Build(changeSet); // verify that the association collections for the Order operation are null ChangeSetEntry orderOperation = operations.Single(p => p.Entity == order); ChangeSetEntry custOperation = operations.Single(p => p.Entity == cust); Assert.IsNull(orderOperation.Associations); Assert.IsNull(orderOperation.OriginalAssociations); Assert.IsNotNull(orderOperation.OriginalEntity); // verify that the association collections for the Customer operation are null Assert.IsNull(custOperation.OriginalEntity); Assert.IsNull(custOperation.Associations); Assert.IsNull(custOperation.OriginalAssociations); // verify that deleted OrderDetails have null associations as well ChangeSetEntry detailOperation = operations.First(p => p.Entity.GetType() == typeof(Order_Detail)); Assert.IsNotNull(detailOperation.OriginalEntity); Assert.IsNull(detailOperation.Associations); Assert.IsNull(detailOperation.OriginalAssociations); }
public void InferredAdd_EntityCollection() { NorthwindEntityContainer ec = new NorthwindEntityContainer(); // add a few existing entities Order order1 = new Order { OrderID = 1 }; Order order2 = new Order { OrderID = 2 }; Order_Detail detail1 = new Order_Detail { OrderID = 2, ProductID = 1 }; ec.LoadEntities(new Entity[] { order1, order2, detail1 }); ((IChangeTracking)ec).AcceptChanges(); Assert.IsFalse(ec.HasChanges); // build a detached graph of a new category and 2 products, // referenced by a detail Order_Detail newDetail1 = new Order_Detail { OrderID = 1, ProductID = 2 }; Category newCategory = new Category { CategoryID = 1 }; Product newProduct1 = new Product { ProductID = 3 }; Product newProduct2 = new Product { ProductID = 4 }; newCategory.Products.Add(newProduct1); newCategory.Products.Add(newProduct2); newDetail1.Product = newProduct1; EntityChangeSet cs = ec.GetChanges(); Assert.IsTrue(cs.IsEmpty); // verify that adding an unattached entity to an EC results in // the expected inferred Adds order1.Order_Details.Add(newDetail1); cs = ec.GetChanges(); Assert.AreEqual(4, cs.AddedEntities.Count); Assert.IsTrue(cs.AddedEntities.Contains(newDetail1)); // the entity added directly Assert.IsTrue(cs.AddedEntities.Contains(newProduct1)); // inferred via Detail.Product ER Assert.IsTrue(cs.AddedEntities.Contains(newCategory)); // inferred via Product.Category ER Assert.IsTrue(cs.AddedEntities.Contains(newProduct2)); // inferred via Category.Products EC // verify that inferred Adds can be state transitioned via subsequent // calls to Attach ec.GetEntitySet <Product>().Attach(newProduct2); newProduct2.ProductName += "x"; cs = ec.GetChanges(); Assert.AreEqual(3, cs.AddedEntities.Count); Assert.AreEqual(1, cs.ModifiedEntities.Count); Assert.IsFalse(cs.AddedEntities.Contains(newProduct2)); Assert.IsTrue(cs.ModifiedEntities.Contains(newProduct2)); // verify that duplicate references aren't added when an // inferred entity is attached Assert.AreEqual(2, ec.GetEntitySet <Product>().Count); }