diff --git a/src/Microsoft.EntityFrameworkCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/Microsoft.EntityFrameworkCore/ChangeTracking/Internal/InternalEntityEntry.cs index bd204f400f3..de59fb66f78 100644 --- a/src/Microsoft.EntityFrameworkCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/Microsoft.EntityFrameworkCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -222,9 +222,6 @@ public virtual void SetPropertyModified( bool changeState = true, bool isModified = true) { - // TODO: Restore original value to reject changes when isModified is false - // Issue #742 - var propertyIndex = property.GetIndex(); _stateData.FlagProperty(propertyIndex, PropertyFlag.Unknown, false); @@ -258,6 +255,11 @@ public virtual void SetPropertyModified( if (changeState) { + if (!isModified + && property.GetOriginalValueIndex() != -1) + { + SetProperty(property, GetOriginalValue(property), setModified: false); + } _stateData.FlagProperty(propertyIndex, PropertyFlag.TemporaryOrModified, isModified); } diff --git a/test/Microsoft.EntityFrameworkCore.Tests/ChangeTracking/PropertyEntryTest.cs b/test/Microsoft.EntityFrameworkCore.Tests/ChangeTracking/PropertyEntryTest.cs index b2c29baa500..ef3829e4781 100644 --- a/test/Microsoft.EntityFrameworkCore.Tests/ChangeTracking/PropertyEntryTest.cs +++ b/test/Microsoft.EntityFrameworkCore.Tests/ChangeTracking/PropertyEntryTest.cs @@ -3,13 +3,10 @@ using System; using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Runtime.CompilerServices; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Specification.Tests; using Xunit; @@ -121,6 +118,41 @@ public void Can_set_and_clear_modified() Assert.False(new PropertyEntry(entry, "Primate").IsModified); } + [Fact] + public void Can_reject_changes_when_clearing_modified_flag() + { + var entity = new Wotty { Id = 1, Primate = "Monkey", Marmate = "Bovril" }; + + var entry = TestHelpers.Instance.CreateInternalEntry( + BuildModel(), + EntityState.Unchanged, + entity); + + var primateEntry = new PropertyEntry(entry, "Primate"); + primateEntry.OriginalValue = "Chimp"; + primateEntry.IsModified = true; + + var marmateEntry = new PropertyEntry(entry, "Marmate"); + marmateEntry.OriginalValue = "Marmite"; + marmateEntry.IsModified = true; + + Assert.Equal(EntityState.Modified, entry.EntityState); + Assert.Equal("Monkey", entity.Primate); + Assert.Equal("Bovril", entity.Marmate); + + primateEntry.IsModified = false; + + Assert.Equal(EntityState.Modified, entry.EntityState); + Assert.Equal("Chimp", entity.Primate); + Assert.Equal("Bovril", entity.Marmate); + + marmateEntry.IsModified = false; + + Assert.Equal(EntityState.Unchanged, entry.EntityState); + Assert.Equal("Chimp", entity.Primate); + Assert.Equal("Marmite", entity.Marmate); + } + [Fact] public void Can_get_name_generic() { @@ -431,6 +463,7 @@ private class Wotty { public int Id { get; set; } public string Primate { get; set; } + public string Marmate { get; set; } } private class FullyNotifyingWotty : HasChangedAndChanging @@ -518,7 +551,7 @@ private abstract class HasChanged : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; - protected void OnPropertyChanged([CallerMemberName]string propertyName = "") + protected void OnPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } @@ -526,7 +559,7 @@ private abstract class HasChangedAndChanging : HasChanged, INotifyPropertyChangi { public event PropertyChangingEventHandler PropertyChanging; - protected void OnPropertyChanging([CallerMemberName]string propertyName = "") + protected void OnPropertyChanging([CallerMemberName] string propertyName = "") => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName)); }