Long away. I just read DataServiceContext.UpdateObjectInternal(entity, failIfNotUnchanged) , which is called directly from UpdateObject(entity) with argument false .
The logic reads as follows:
- If already changed, return; (Short circuit)
- If it has not changed, drop it if
failIfNotUnchanged ; (true only from ChangeState() ) - The rest of the setting state will change. (no data checks occurred)
Thus, when looking at it, UpdateObject does not care / check the internal state of the object, just an enumeration of State . This makes updates a bit inaccurate when there are no changes.
However, I think your problem is that in the 2nd block of OP code, you check the HasChanges extension before calling UpdateObject . Objects are only illustrious POCOs (as you can read in your Reference.cs (Show hidden files and then in the help service)). They have obvious properties and several On- operations to notify you of a change. What they do not do inside is the state of the track. In fact, there is an EntityDescriptor object associated with the object that is responsible for tracking the state in EntityTracker.TryGetEntityDescriptor(entity) .
The bottom line of the operation actually works very simply, and I think you just need to make your code like
Customer.Address1 = "Fred"; ctx.UpdateObject(Customer); if (!ctx.HasChanges()) return; ctx.SaveChanges();
Although, as we know now, this will always tell HasChanges == true, so you can also skip checking.
But do not despair! The partial classes provided by your service can be extended to do exactly what you want. This is fully boilerplate code, so you can write .tt or some other code. Regardless, just configure this for your objects:
namespace ODataClient.ServiceReference1 // Match the namespace of the Reference.cs partial class { public partial class Books // Your entity { public bool HasChanges { get; set; } = false; // Your new property! partial void OnIdChanging(int value) // Boilerplate { if (Id.Equals(value)) return; HasChanges = true; } partial void OnBookNameChanging(string value) // Boilerplate { if (BookName == null || BookName.Equals(value)) return; HasChanges = true; } // etc, ad nauseam } // etc, ad nauseam }
But now this works fine and expresses the OP similarly:
var book = context.Books.Where(x => x.Id == 2).SingleOrDefault(); book.BookName = "W00t!"; Console.WriteLine(book.HasChanges);
NTN!