diff --git a/Source/Tests/TrackableEntities.Client.Tests.Entities/NorthwindModels/PriorityOrder.cs b/Source/Tests/TrackableEntities.Client.Tests.Entities/NorthwindModels/PriorityOrder.cs new file mode 100644 index 00000000..0a0118dd --- /dev/null +++ b/Source/Tests/TrackableEntities.Client.Tests.Entities/NorthwindModels/PriorityOrder.cs @@ -0,0 +1,21 @@ +using System; +using Newtonsoft.Json; + +namespace TrackableEntities.Client.Tests.Entities.NorthwindModels +{ + [JsonObject(IsReference = true)] + public class PriorityOrder : Order + { + private string _priorityPlan; + public string PriorityPlan + { + get { return _priorityPlan; } + set + { + if (value == _priorityPlan) return; + _priorityPlan = value; + NotifyPropertyChanged(() => PriorityPlan); + } + } + } +} diff --git a/Source/Tests/TrackableEntities.Client.Tests.Entities/TrackableEntities.Client.Tests.Entities.csproj b/Source/Tests/TrackableEntities.Client.Tests.Entities/TrackableEntities.Client.Tests.Entities.csproj index 7fbc899b..243b33f0 100644 --- a/Source/Tests/TrackableEntities.Client.Tests.Entities/TrackableEntities.Client.Tests.Entities.csproj +++ b/Source/Tests/TrackableEntities.Client.Tests.Entities/TrackableEntities.Client.Tests.Entities.csproj @@ -53,6 +53,7 @@ + diff --git a/Source/Tests/TrackableEntities.Client.Tests.Extensions/ChangeTrackingExtensionsTests.cs b/Source/Tests/TrackableEntities.Client.Tests.Extensions/ChangeTrackingExtensionsTests.cs index 23eb9e3c..924f7d7a 100644 --- a/Source/Tests/TrackableEntities.Client.Tests.Extensions/ChangeTrackingExtensionsTests.cs +++ b/Source/Tests/TrackableEntities.Client.Tests.Extensions/ChangeTrackingExtensionsTests.cs @@ -122,8 +122,9 @@ public void MergeChanges_Should_Set_TrackingState_To_Unchanged_For_Added_Order_W { // Arrange var database = new MockNorthwind(); - var origOrder = new Order + var origOrder = new PriorityOrder { + PriorityPlan = "Silver", OrderDate = DateTime.Parse("1996-07-04"), CustomerId = "ALFKI" }; diff --git a/Source/Tests/TrackableEntities.EF.5.Tests/NorthwindDbContextTests.cs b/Source/Tests/TrackableEntities.EF.5.Tests/NorthwindDbContextTests.cs index 8940a409..24d4aa34 100644 --- a/Source/Tests/TrackableEntities.EF.5.Tests/NorthwindDbContextTests.cs +++ b/Source/Tests/TrackableEntities.EF.5.Tests/NorthwindDbContextTests.cs @@ -399,6 +399,27 @@ public void Apply_Changes_Should_Mark_Order_Modified_With_OrderDetails_Added_Mod Assert.AreEqual(EntityState.Modified, context.Entry(detail2).State); Assert.AreEqual(EntityState.Deleted, context.Entry(detail3).State); Assert.AreEqual(EntityState.Unchanged, context.Entry(detail4).State); + Assert.AreEqual(EntityState.Unchanged, context.Entry(detail1.Product).State); + } + + [Test] + public void Apply_Changes_Should_Mark_Unchanged_Product_Of_Added_OrderDetail_Of_Added_Order_As_Unchanged() + { + // Arrange + var context = TestsHelper.CreateNorthwindDbContext(CreateNorthwindDbOptions); + var order = new MockNorthwind().Orders[0]; + var orderDetail = order.OrderDetails[0]; + var product = orderDetail.Product; + order.TrackingState = TrackingState.Added; + orderDetail.TrackingState = TrackingState.Added; + + // Act + context.ApplyChanges(order); + + // Assert + Assert.AreEqual(EntityState.Added, context.Entry(order).State); + Assert.AreEqual(EntityState.Added, context.Entry(orderDetail).State); + Assert.AreEqual(EntityState.Unchanged, context.Entry(product).State); } [Test] diff --git a/Source/TrackableEntities.Client/ChangeTrackingExtensions.cs b/Source/TrackableEntities.Client/ChangeTrackingExtensions.cs index 36b80596..ddd58c09 100644 --- a/Source/TrackableEntities.Client/ChangeTrackingExtensions.cs +++ b/Source/TrackableEntities.Client/ChangeTrackingExtensions.cs @@ -221,7 +221,7 @@ private static void SetEntityProperties(this ITrackable targetItem, ITrackable s #if SILVERLIGHT || NET40 foreach (var prop in targetItem.GetType().GetProperties().Where(p => p.CanWrite) #else - foreach (var prop in targetItem.GetType().GetTypeInfo().DeclaredProperties + foreach (var prop in targetItem.GetType().BaseTypes().SelectMany(t => t.GetTypeInfo().DeclaredProperties) .Where(p => p.CanWrite && !p.GetMethod.IsPrivate) #endif .Except(targetItem.GetNavigationProperties(false).Select(np => np.Property))) diff --git a/Source/TrackableEntities.EF.5/DbContextExtensions.cs b/Source/TrackableEntities.EF.5/DbContextExtensions.cs index 2154a50d..4ad43fc0 100644 --- a/Source/TrackableEntities.EF.5/DbContextExtensions.cs +++ b/Source/TrackableEntities.EF.5/DbContextExtensions.cs @@ -97,13 +97,11 @@ private static void ApplyChanges(this DbContext context, // Set state for child collections context.ApplyChangesOnProperties(item, visitationHelper); return; - } + } - // Exit if parent is added or deleted, - // and it's not a M-1 relation + // Exit if parent is deleted and not a M-1 relation if (parent != null - && (parent.TrackingState == TrackingState.Added - || parent.TrackingState == TrackingState.Deleted) + && (parent.TrackingState == TrackingState.Deleted) && !context.IsRelatedProperty(parent.GetType(), propertyName, RelationshipType.ManyToOne)) return; @@ -126,9 +124,14 @@ private static void ApplyChanges(this DbContext context, return; } - // Set state to Added on parent only + // Set state to Added if item marked as Added if (item.TrackingState == TrackingState.Added - && (state == null || state == TrackingState.Added)) + && (state == null || state == TrackingState.Added) + // Or if parent marked as Added and 1-M or 1-1 relation + || (parent != null + && parent.TrackingState == TrackingState.Added + && (context.IsRelatedProperty(parent.GetType(), propertyName, RelationshipType.OneToMany) + || context.IsRelatedProperty(parent.GetType(), propertyName, RelationshipType.OneToOne)))) { context.Entry(item).State = EntityState.Added; context.ApplyChangesOnProperties(item, visitationHelper); @@ -565,6 +568,9 @@ private static bool IsRelatedProperty(this DbContext dbContext, case RelationshipType.ManyToMany: return navProp.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many && navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many; + case RelationshipType.OneToMany: + return navProp.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One + && navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many; default: return false; } @@ -603,6 +609,7 @@ enum RelationshipType ManyToOne, OneToOne, ManyToMany, + OneToMany } #endregion