Entity Framework 6 - DataServiceContext Detect Has Changes

c# entity-framework-6 odata wcf wcf-data-services-client


Entity Framework 6 is used by a WCF server application that I have.

My client application uses a DataServiceContext to access OData from the server, and I want to be able to check the context's HasChanges() method to see whether any of the data has changed.

I experimented with the following extension technique:

    public static bool HasChanges(this  DataServiceContext ctx)
        // Return true if any Entities or links have changes
        return ctx.Entities.Any(ed => ed.State != EntityStates.Unchanged) || ctx.Links.Any(ld => ld.State != EntityStates.Unchanged);

However, even if an entity it is tracking has changed, it always returns false.

For instance, the code below always returns before calling SaveChanges since I have a monitored entity named Customer ().

    Customer.Address1 = "Fred"
    if not ctx.HasChanges() then return

If I comment out the if not, return ctx.HasChanges() line of code, the changes are saved successfully so I'm happy that the entity has received the change and is able to save it.

Although I can't prove it from my code, it appears that the context is tracking the change is.

Can somebody explain how to find out if a DataServiceContext has undergone changes?

10/29/2015 11:20:49 AM

Accepted Answer

quite unusual. I recently finished readingDataServiceContext.UpdateObjectInternal(entity, failIfNotUnchanged) , which receives a direct call fromUpdateObject(entity) with afalse argument.

The reasoning follows:

  • if modified already, revert; (short-circuit)
  • Throw if not unchanged.failIfNotUnchanged (Only true fromChangeState() )
  • Set the state to modified if not. (There were no data checks)

Accordingly, it appears thatUpdateObject does not consider or examine the entity's internal state, only theState enum. As a result, when there are no changes, updates seem a bit wrong.

However, I believe the second block of code in the OP is where your issue is. Please check your extension.HasChanges phoning from beforeUpdateObject The organizations are merely enhanced POCOs, as you can see in yourReference.cs (First, under the Service Reference, select Show Hidden Files). Along with a few less noticeable ones, they haveOn- actions to alert about changes. They track state internally, which is what they do. There actually is anEntityDescriptor connected with the organization in charge of state tracking inEntityTracker.TryGetEntityDescriptor(entity) .

In essence, operations are actually very straightforward, and I believe you just need to make your code look like

Customer.Address1 = "Fred";
if (!ctx.HasChanges()) return;

However, given what we know at this point, you may skip the check because HasChanges == true will be reported.

But don't give up! Your service reference's partial classes can be expanded to provide any desired functionality. You might wish to write a.tt or another codegen since it is entirely boilerplate code. Whatever the case, just adjust this to your entities:

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

Now, though, this works fantastically and is equally expressive as the OP:

var book = context.Books.Where(x => x.Id == 2).SingleOrDefault();
book.BookName = "W00t!";


10/30/2015 1:54:11 PM

Popular Answer


Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow