public void Existing_Parent_With_Added_Children_Should_Have_Children_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(order);
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var addedDetail1 = new OrderDetail
            {
                ProductId = 1,
                Product = database.Products[0],
                Quantity = 10,
                UnitPrice = 20M
            };
            var addedDetail2 = new OrderDetail
            {
                ProductId = 2,
                Product = database.Products[1],
                Quantity = 20,
                UnitPrice = 30M
            };

            // Act
            orderDetails.Add(addedDetail1);
            orderDetails.Add(addedDetail2);

            // Assert
            Assert.Equal(TrackingState.Added, addedDetail1.TrackingState);
            Assert.Equal(TrackingState.Added, addedDetail2.TrackingState);
        }
        public void Existing_Parent_With_Children_Should_Have_Children_Marked()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(order);
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var addedDetail = new OrderDetail
                {
                    ProductId = 1,
                    Product = database.Products[0],
                    Quantity = 10,
                    UnitPrice = 20M
                };
            var modifiedDetail = orderDetails[0];
            var deletedDetail = orderDetails[1];
            addedDetail.Order = order;
            modifiedDetail.Order = order;
            deletedDetail.Order = order;

            // Act
            modifiedDetail.UnitPrice++;
            orderDetails.Remove(deletedDetail);
            orderDetails.Add(addedDetail);

            // Assert
            Assert.Equal(TrackingState.Added, addedDetail.TrackingState);
            Assert.Equal(TrackingState.Modified, modifiedDetail.TrackingState);
            Assert.Equal(TrackingState.Deleted, deletedDetail.TrackingState);
        }
        public void MergeChanges_Should_Merge_Updates_For_Unchanged_Order_With_Changed_OrderDetails()
        {
            // Arrange
            var database = new MockNorthwind();
            var origOrder = database.Orders[0];
            var product = database.Products.Single(p => p.ProductId == 14);
            origOrder.OrderDetails.Add(new OrderDetail { ProductId = 14, OrderId = 10249, Quantity = 9, UnitPrice = 18.6000M, Product = product });
            var unchangedDetail = origOrder.OrderDetails[0];
            var modifiedDetail = origOrder.OrderDetails[1];
            var deletedDetail = origOrder.OrderDetails[3];
            var changeTracker = new ChangeTrackingCollection<Order>(origOrder);
            origOrder.OrderDetails[1].Product.ProductName = "xxx";
            origOrder.OrderDetails[2].Quantity++;
            origOrder.OrderDetails[2].ProductId = 1;
            var newUnitPrice = origOrder.OrderDetails[2].UnitPrice + 1;
            origOrder.OrderDetails.RemoveAt(3);
            var addedDetail = new OrderDetail {ProductId = 51, OrderId = 10249, Quantity = 40, UnitPrice = 42.4000M};
            origOrder.OrderDetails.Add(addedDetail);

            var changes = changeTracker.GetChanges();
            var updatedOrder = UpdateOrdersWithDetails(database, changes)[0];

            // Act
            changeTracker.MergeChanges(updatedOrder);

            // Assert
            Assert.Contains(unchangedDetail, origOrder.OrderDetails); // Unchanged present
            Assert.Equal("xxx", origOrder.OrderDetails[1].Product.ProductName); // Prod name updated
            Assert.Equal(updatedOrder.OrderDetails[1].ProductId, origOrder.OrderDetails[2].Product.ProductId); // Changed Product set
            Assert.Equal(newUnitPrice, origOrder.OrderDetails[2].UnitPrice); // Db-generated value set
            Assert.Equal(updatedOrder.OrderDetails[2].Product.ProductId, origOrder.OrderDetails[3].Product.ProductId); // Added detail Product set
            Assert.True(origOrder.OrderDetails.All(d => d.TrackingState == TrackingState.Unchanged)); // Details unchanged
            Assert.Same(addedDetail, origOrder.OrderDetails.Single(d => d.ProductId == 51)); // Ref equality
            Assert.Same(modifiedDetail, origOrder.OrderDetails.Single(d => d.ProductId == 42)); // Ref equality
            Assert.DoesNotContain(deletedDetail, origOrder.OrderDetails); // Detail deleted
            ICollection cachedDeletes = ((ITrackingCollection)origOrder.OrderDetails).GetChanges(true);
            Assert.Empty(cachedDeletes); // Cached deletes have been removed
        }
        public void GetChanges_On_Deleted_Order_With_Details_Should_Return_Marked_Children_Deleted()
        {
            // NOTE: Removed order with added detail should exclude added detail
            // Removed order with deleted detail should include deleted detail

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(order);
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var unchangedDetail = orderDetails[0];
            var modifiedDetail = orderDetails[1];
            var deletedDetail = orderDetails[2];
            var addedDetail = new OrderDetail
            {
                ProductId = 1,
                Product = database.Products[0],
                Quantity = 10,
                UnitPrice = 20M
            };
            orderDetails.Add(addedDetail);
            modifiedDetail.UnitPrice++;
            orderDetails.Remove(deletedDetail);
            changeTracker.Remove(order);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            var changedOrder = changes.First();
            var changedExistingDetail = changedOrder.OrderDetails.SingleOrDefault(d => d.ProductId == unchangedDetail.ProductId);
            var changedModifiedDetail = changedOrder.OrderDetails.SingleOrDefault(d => d.ProductId == modifiedDetail.ProductId);
            var changedAddedDetail = changedOrder.OrderDetails.SingleOrDefault(d => d.ProductId == addedDetail.ProductId);
            var changedDeletedDetail = changedOrder.OrderDetails.SingleOrDefault(d => d.ProductId == deletedDetail.ProductId);
            Assert.Equal(TrackingState.Deleted, changedOrder.TrackingState);
            Assert.Equal(3, changedOrder.OrderDetails.Count);
            Assert.Equal(TrackingState.Deleted, changedModifiedDetail.TrackingState);
            Assert.Equal(TrackingState.Deleted, changedExistingDetail.TrackingState);
            Assert.Equal(TrackingState.Deleted, changedDeletedDetail.TrackingState);
            Assert.Null(changedAddedDetail);
            Assert.Equal(TrackingState.Unchanged, addedDetail.TrackingState);
        }
        public void GetChanges_On_Added_Order_With_Details_Should_Return_Marked_Children_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true) {order};
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var unchangedDetail = orderDetails[0];
            var modifiedDetail = orderDetails[1];
            var deletedDetail = orderDetails[2];
            var addedDetail = new OrderDetail
            {
                ProductId = 1,
                Product = database.Products[0],
                Quantity = 10,
                UnitPrice = 20M
            };
            orderDetails.Add(addedDetail);
            modifiedDetail.UnitPrice++;
            orderDetails.Remove(deletedDetail);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            var changedOrder = changes.First();
            var changedExistingDetail = changedOrder.OrderDetails.Single(d => d.ProductId == unchangedDetail.ProductId);
            var changedModifiedDetail = changedOrder.OrderDetails.Single(d => d.ProductId == modifiedDetail.ProductId);
            var changedAddedDetail = changedOrder.OrderDetails.Single(d => d.ProductId == addedDetail.ProductId);
            Assert.Equal(TrackingState.Added, changedOrder.TrackingState);
            Assert.Equal(3, changedOrder.OrderDetails.Count);
            Assert.Equal(TrackingState.Added, changedModifiedDetail.TrackingState);
            Assert.Equal(TrackingState.Added, changedAddedDetail.TrackingState);
            Assert.Equal(TrackingState.Added, changedExistingDetail.TrackingState);
            Assert.DoesNotContain(deletedDetail, changedOrder.OrderDetails);
        }
        public void GetChanges_On_Unchanged_Order_With_Details_Should_Return_Marked_Children()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var order3 = database.Orders[3];
            var changeTracker = new ChangeTrackingCollection<Order>(order, order3);
            order3.OrderDate += new System.TimeSpan(1, 0, 0, 0); // + one day
            order3.Customer.CustomerName += " (test)";
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var unchangedDetail = orderDetails[0];
            var modifiedDetail = orderDetails[1];
            var deletedDetail = orderDetails[2];
            var addedDetail = new OrderDetail
            {
                ProductId = 1,
                Product = database.Products[0],
                Quantity = 10,
                UnitPrice = 20M
            };
            orderDetails.Add(addedDetail);
            modifiedDetail.UnitPrice++;
            orderDetails.Remove(deletedDetail);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            var changedOrder = changes.First();
            var changedOrder3 = changes[1];
            var changedModifiedDetail = changedOrder.OrderDetails.Single(d => d.ProductId == modifiedDetail.ProductId);
            var changedAddedDetail = changedOrder.OrderDetails.Single(d => d.ProductId == addedDetail.ProductId);
            var changedDeletedDetail = changedOrder.OrderDetails.Single(d => d.ProductId == deletedDetail.ProductId);
            Assert.Equal(TrackingState.Unchanged, changedOrder.TrackingState);
            Assert.Equal(3, changedOrder.OrderDetails.Count);
            Assert.Equal(TrackingState.Modified, changedModifiedDetail.TrackingState);
            Assert.Equal(TrackingState.Added, changedAddedDetail.TrackingState);
            Assert.Equal(TrackingState.Deleted, changedDeletedDetail.TrackingState);
            Assert.DoesNotContain(unchangedDetail, changedOrder.OrderDetails);
            Assert.NotNull(order.Customer);
            Assert.NotNull(order3.Customer);
            Assert.NotNull(changedOrder.Customer);
            Assert.NotNull(changedOrder3.Customer);
            Assert.True(object.ReferenceEquals(order.Customer, order3.Customer));
            Assert.False(object.ReferenceEquals(order.Customer, changedOrder.Customer));
            Assert.True(object.ReferenceEquals(changedOrder.Customer, changedOrder3.Customer));
        }