Trackable Entities versus Self-Tracking Entities

In this blog post I’d like to perform an in-depth comparison between my own Trackable Entities framework and the now deprecated Self-Tracking Entities, written by the Entity Framework team at Microsoft. Because STE’s were discontinued with EF v4, there’s the mistaken notion that tracking entity state is generally a bad idea. Nothing could be further from the truth.

Consider the following scenario. You have an Order entity with related OrderDetails. You want to create, update and delete some of the OrderDetails within the same transaction. If one of the updates fails, for example by not specifying a valid ProductId, none of the other updates should succeed, and the entire transaction should be rolled back.  This means you need to pass all the details (added, modified, deleted) to the same service operation. Without tracking entity state, you would have to pass each set of details separately. For example:

public Order PutOrder(Order order, List<OrderDetail> addedDetails,
    List<OrderDetail> modifiedDetails, List<OrderDetail> deletedDetails)
{
    // TODO: Save changes
}

On the client you still have to keep track of which details were added, modified and deleted, so that you can group them accordingly. Then on the server you have to figure out how best to return inserted and updated details to the client with database-generated identity and concurrency values, probably by retrieving the updated order with details from the database.

Change-tracking solves this problem.  In fact, this is precisely how WCF Data Services, an implementation of the OData spec, performs batch updates.  There is a client-side change-tracker which sets entity state as you call methods on a context object (AddObject, UpdateObject, DeleteObject, SetLink), so that updates can be batched when changes are saved.  In fact, WCF Data Services is one of the technologies recommended by Microsoft as a replacement for STE’s.  Nevertheless, OData is not necessarily going to give you as much control over the API surface of your web services. While it is possible to expose an OData service via ASP.NET Web API controllers, the overall intent of OData is to create queryable syndication data feeds – using OData just to get change-tracking and batch updates may be overkill for most n-tier scenarios.

So where did Self-Tracking Entities go wrong?

To answer this question, let’s take a look at code produced by the STE template.

[DataContract(IsReference = true)]
[KnownType(typeof(Category))]
[KnownType(typeof(OrderDetail))]
public partial class Product : IObjectWithChangeTracker, INotifyPropertyChanged
{
    [DataMember]
    public string ProductName
    {
        get { return _productName; }
        set
        {
            if (_productName != value)
            {
                _productName = value;
                OnPropertyChanged("ProductName");
            }
        }
    }
    private string _productName;

    [DataMember]
    public TrackableCollection<OrderDetail> OrderDetails
    {
        get
        {
            if (_orderDetails == null)
            {
                _orderDetails = new TrackableCollection<OrderDetail>();
                _orderDetails.CollectionChanged += FixupOrderDetails;
            }
            return _orderDetails;
        }
        set
        {
            if (!ReferenceEquals(_orderDetails, value))
            {
                if (ChangeTracker.ChangeTrackingEnabled)
                {
                    throw new InvalidOperationException("Cannot set the FixupChangeTrackingCollection when ChangeTracking is enabled");
                }
                if (_orderDetails != null)
                {
                    _orderDetails.CollectionChanged -= FixupOrderDetails;
                }
                _orderDetails = value;
                if (_orderDetails != null)
                {
                    _orderDetails.CollectionChanged += FixupOrderDetails;
                }
                OnNavigationPropertyChanged("OrderDetails");
            }
        }
    }
    private TrackableCollection<OrderDetail> _orderDetails;

    [DataMember]
    public ObjectChangeTracker ChangeTracker
    {
        get
        {
            if (_changeTracker == null)
            {
                _changeTracker = new ObjectChangeTracker();
                _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
            }
            return _changeTracker;
        }
        set
        {
            if (_changeTracker != null)
            {
                _changeTracker.ObjectStateChanging -= HandleObjectStateChanging;
            }
            _changeTracker = value;
            if (_changeTracker != null)
            {
                _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
            }
        }
    }
    private ObjectChangeTracker _changeTracker;

    // Change Tracking Code ...

    // Serialization Code ...

    // Association Fixup Code ...
}

I omitted most of the other properties, but altogether the Product class ends up with over 350 lines of code!  And most of that is plumbing code handling various aspects of change-tracking and serialization. But it gets worse. You can see that Product implements an interface called IObjectWithChangeTracker, which has a ChangeTracker property of type ObjectChangeTracker, which in turn has properties for ObjectState, ObjectsRemovedFromCollectionProperties, ObjectsAddedToCollectionProperties, OriginalValues and ExtendedProperties.

The sad part about all this is that the extra baggage added by these properties and methods is almost entirely unnecessary.  There’s no need to attach a change tracker to each entity, nor should it be necessary to insert change-tracking and serialization code into each entity.  Those things belong elsewhere. In short, STE’s violate the principle of Separation of Concerns (SoC).

Why were STE’s designed this way?  There are probably several reasons. For one, they modeled STE’s after EF-specific entities, which implement IEntityWithChangeTracker.  Second, NuGet did not exist at that time, making it difficult to deploy an assembly with a client-side change-tracker that did not depend on the Entity Framework, which forced them to use T4 code generation instead. Third, they generated the same entities for both client and server, with server code that did not belong on the client and client code that did not belong on the server. Fourth, they were still tied to a Model First approach with an EDMX file, and because Code First was not yet fully baked, they had to take Independent Associations into account. Fifth, they brought over original property values rather than requiring the use of row versions for concurrency. And sixth, the client-side code generally is too tightly coupled with the server-side code that reads the entity state in order to perform updates.

In addition, the API was rather rough around the edges.  Here is list of complaints I had at the time:

  • No GetChanges method to obtain just the entities that had changed.
  • Items removed from child collections were not automatically marked as deleted – you had to call MarkAsDeleted explicitly.
  • Marking a parent as deleted did not mark child entities as deleted – you had to do it manually.
  • AcceptChanges was not recursive – you had to call it on both parent and child entities.

The good news is that these architectural and technical flaws are avoidable.  Some of them could have been avoided at the time, and others can now be avoided because we have additional options. For example, Code First is now mature, and we have NuGet for distributing a client assembly that is not tied to Entity Framework. We still have T4 templates, but they can be used more narrowly for generating separate client and server entities.  In addition, it is now possible to leverage other tools for increasing developer productivity, such as the EF Power Tools (although they need an overhaul), and scaffolding for ASP.NET Web API.

So how does Trackable Entities avoid the pitfalls that doomed STE’s?

Before answering this question, I would like to point out that Trackable Entities actually predates STE’s and EF4. Back in 2008, I published an MSDN Magazine article which provided a solution to the need for change-tracking entities across service boundaries in a way that does not couple entities to any particular persistence stack.  (I even showed how it could be done with both EF and LINQ to SQL.)  Then in 2010 I updated my solution with Trackable DTO’s and T4 templates that generated client-entities based on WCF metadata. My Trackable Entities project represents a further evolution that is not coupled to any web service stack (be it ASP.NET Web API or Windows Communication Foundation).

Now to answer the question. Architecturally, Trackable Entities adheres to the principle of SoC by placing all change-tracking logic in a class called ChangeTrackingCollection<T>, which extends ObservableCollection<T> (for data-binding friendliness).  The change tracker marks entities as Added, Modified or Deleted (deleted items are also cached). To track some items, just add them to the collection. Simple! Smile

The client assembly is a Portable Class Library (so it runs on just about any client) and is deployed as a NuGet package. Its only dependency is on a TrackableEntities.Common package, which contains the ITrackable interface, and on Json.Net, for efficient serialization.  Here is the client version of the Product entity (with just ProjectName and OrderDetails properties – just like the STE sample I showed earlier). Aside from properties for TrackingState and ModifiedProperties, there’s no extra code for change-tracking or serialization. ModelBase only contains an implementation of INotifyPropertyChanged, and this class is not generated because it’s located in the client library referenced via NuGet.

[JsonObject(IsReference = true)]
[DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
public partial class Product : ModelBase<Product>, ITrackable
{
    public Product()
    {
        this.OrderDetails = new ChangeTrackingCollection<OrderDetail>();
    }

    [DataMember]
    public string ProductName
    {
        get { return _ProductName; }
        set
        {
            if (value == _ProductName) return;
            _ProductName = value;
            NotifyPropertyChanged(m => m.ProductName);
        }
    }
    private string _ProductName;

    [DataMember]
    public ChangeTrackingCollection<OrderDetail> OrderDetails
    {
        get { return _OrderDetails; }
        set
        {
            if (Equals(value, _OrderDetails)) return;
            _OrderDetails = value;
            NotifyPropertyChanged(m => m.OrderDetails);
        }
    }
    private ChangeTrackingCollection<OrderDetail> _OrderDetails;

    [DataMember]
    public ICollection<string> ModifiedProperties { get; set; }

    [DataMember]
    public TrackingState TrackingState { get; set; }
}

Another way that Trackable Entities achieves Separation of Concerns is by providing separate T4 templates for client and server entity generation. Client-side entities automatically track changes to client entities and implement INotifyPropertyChanged, but on the server there’s no need for such things. Here is the same Product entity generated for the server.

[JsonObject(IsReference = true)]
[DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
public partial class Product : ITrackable
{
    public Product()
    {
        this.OrderDetails = new List<OrderDetail>();
    }

    [DataMember]
    public string ProductName { get; set; }
    [DataMember]
    public List<OrderDetail> OrderDetails { get; set; }

    [DataMember]
    public TrackingState TrackingState { get; set; }
    [DataMember]
    public ICollection<string> ModifiedProperties { get; set; }
}

As you can see, there is nothing related to EF and nothing that would require tight coupling on the client. TrackingState is simply an enum and is serialized (Json or Xml) as an Integer. ModifiedProperties is represented as a collection of strings and is only present on modified entities.

On the server things are also much simpler, and everything is based on Code First, so there’s no EDMX file to contend with.  There is an ApplyChanges method you call on your DbContext-derived class, which recursively walks the object graph, setting EntityState by reading each entity’s TrackingState. Then there’s an AcceptChanges method which recursively sets entities to an Unchanged state before they are returned to the client. In total, there are just two public methods with two private helper methods and about 100 lines of code. That’s it!  In contrast, STE’s generate server-side code with 28 methods, 4 helper classes and over 1200 lines of code.

I hope this post helps developers get past any aversion they might have to change-tracking from having been burned by STE’s.  One of the alternatives to STE’s recommended by Microsoft is “Entity Framework APIs,” where they refer to an excellent book on DbContext by Julie Lerman and Rowan Miller.  But then they issue the warning that “this is a complex problem to solve” and steer you back to WCF Data Services.  I would heartily agree that it is a complex problem to solve, but it has been solved! So instead of trying to re-invent the wheel, I urge you (at the risk of sounding self-serving) to give my Trackable Entities a try. Smile

Before closing out, I’d like to mention that Trackable Entities is not just a set of NuGet packages. I’ve deployed it to the Visual Studio Gallery as extensions to both VS 2012 and VS 2013. There is also a Getting Started guide and accompanying screencast. And both ASP.NET Web API and WCF are supported.  What you get is a set of multi-project templates that spin up end-to-end solutions with templates that leverage scaffolding (for ASP.NET Web API), or provide a VS item template (for WCF), and give you service operations that handle all the CRUD. Cheers!

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged . Bookmark the permalink.

48 Responses to Trackable Entities versus Self-Tracking Entities

  1. FWIW, the WCF Services recommendation was made before WebAPI existed. 🙂

    • Hatem gamil says:

      Hi julie, i am a big fan of u, i have listened to all ur videos in plural sight about ef and it.s great.we are working on a project with n-tier architecture using ef4 and unfortunately we used ste tempalte and we are facing a alot of problems using this template. The first problem we faced is “Accept changes cant continue because the objects key values conflict with Another object in the object state manager” we dont know why we get it on updating some entities in database.
      Second issue: we have to use stored proc on inserting some entities so we have to implement a stored proc for update and delete which we dont want to implememt as for insertion we have to because the primary key of some entities is not identity column in database ,it is generated from another stored proc executed inside the insertion procedure.

      • Tony Sneed says:

        To ask Julie a question, you should post to her blog on the Data Farm. But you might want to try my Trackable Entities to see if it addresses the first issue.

  2. Hatem gamil says:

    Can u please post how can i use trackable entities in n-tier application where my clinet is wpf

    • Tony Sneed says:

      ChangeTrackingCollection extends ObservableCollection, so you just bind the data grid directly to it. Otherwise it’s the same, so just copy code from the Console client after using the Trackable Web API or WCF template. On the docs page for the CodePlex site, there is a Getting Started guide with a screencast you can watch. Cheers!

  3. Hatem gamil says:

    Thanks tony vmuch

  4. Nachi says:

    Is there a way to reject changes? I want to Data Bind entity, however if use cancels the original state need to be restored, on client. Do not want to visit server again.

    • Tony Sneed says:

      What you need is Simple MVVM Toolkit! It has a ViewModelDetail base class which implements IEditableObject by cloning an entity when an edit begins, and reverts to the original entity if the edit is cancelled. Notice this is the responsibility of the view model, rather than the model. So there’s nothing to stop you from using Trackable Entities together with Simple MVVM Toolkit! One of my goals in the not too distant future is to create a sample app for this scenario. Cheers, Tony

      • Sean says:

        Hi Tony, I realize this is very old but I’m very interested in seeing that demo app (the one which would show ViewModelDetail : IEditableObject working together with Trackable Entities. I’m building a WPF app that does not use services but that will be using direct database access. I’m trying to learn out to use IEditableObject with Self tracking entities in this scenario. I couldn’t find any links specifically to the sample you referred to in this comment. Thanks, Sean!

  5. Olivier says:

    Very interesting post.
    I’m still using STE with EF5 because we started as a model first approach on an existing complex database and are currently targeting WFP/Silverlight clients. We improved the generated code to only update modified columns when the database. Furthermore, my CRUD WCF data access layer is generated with t4 templates as well.
    Now I need to target ASP.NET MVC (and Json) and would like to reuse most of my existing codebase (entities and services). Ultimately I would also agree to use new t4 templates over my edmx file to generate your Trackable Entities and a new CRUD WCF Service. Is it possible ?

    • Tony Sneed says:

      @Oliver: The answer depends on your EDMX model and whether you are using stored procedures. If you have not customized your EDMX model and are not using stored procedures, upgrading from STE’s to Trackable Entities does not required a great deal of work. Trackable Entities support EF5 with VS 2012 and WCF. However, it uses Code First rather than an EDMX model. TE uses the EF Power Tools to reverse engineer an existing database to a Code First project with T4 templates for trackable entities. If you are comfortable converting from model-first to code-first, then I would recommend using TE’s, as STE’s have been deprecated by Microsoft.

  6. Bobby Dowling says:

    Hi Tony,

    I’ve looked through your code (especially ChangeTrackingCollection) and thoroughly enjoy what you’ve done. Thanks for all of the time, energy and effort you’ve obviously put in – not just in the plumbing, but also the tooling and documentation. Great job. And you are a fellow Dallas inhabitant too, so kudos to you for that (I’m in Ft. Worth).

    Currently, I am writing a .Net Web API to service a Java-based client, so unfortunately, I cannot make use of your solution at the moment though, I’ve definitely shelved some ideas for future reference/use and will remember your solution when I can put it to use.

    For my current project, including a web-based SPA app, I am using one of the few suggestions Julie called out in her book – passing the original values to the client, having the client mark adds/updates and then letting EF’s change-tracking functionality do the heavy lifting… either this, or I’ll use a related suggestion of hers, to load the original values on ApplyChanges(). This seems straight-forward, works great when you don’t have the luxury of the .Net runtime at your disposal and prevents me from having to manually recurse the graph myself, adding, updating and removing everything based on keys/missing entities (for deletes)… and then recursively walking EF’s ChangeTracker entries to mark unchanged items back to an unchanged state. Yikes.

    Or course, Julie’s solution does tie me to EF, causes the client to mark state and either causes an increase in the client payload and/or another trip to the DB, but it’s what I got.

    Thanks again. You actually got me thinking down then trackable entity path again, which led me to Julie’s book. Haven’t thought about it since STEs and was actually just going to manually walk the client graph, as I mentioned earlier.

    Bobby

    • Tony Sneed says:

      Hi Bobby,

      Thanks for checking out the Trackable Entities toolkit! Here’s what I would recommend for your scenario. Use the server-side piece of TE to handle the Entity Framework API. That way, you can benefit from the Visual Studio templates for creating a Web API project that uses Trackable Entities with Entity Framework to persist changes in a disconnected manner – without incurring additional trips to the database. Just remove the client projects and keep the server projects. (There is also a template that uses Repository and Unit of Work patterns.) What you get is three handy methods:

      1) ApplyChanges: This walks the object graph of one or more entities, persisting inserts, updates and deletes in a single transaction. This uses the DbContext API for setting Entity State (as Julie describes in her book), but it does everything in the correct order and handles many-to-many relationships.

      2) LoadRelatedEntities: This populates reference properties up and down the object graph, and it does so in an efficient and asynchronous manner.

      3) AcceptChanges: This reverts change state on all entities in the graph to an UnChanged state, so that they are returned to the client, along with db-generated values, such as identity columns and concurrency tokens.

      So the question is then, what about the client? If it’s a Java or JavaScript client, you can set the change-state manually, or use whatever mechanism you like. All you need to do is add a TrackingState field to each entity (perhaps using an interface for get-set access). The field just needs to be a numeric value corresponding to the TrackingState enum (with Unchanged equal to zero). If you’d like to do partial updates, just add a ModifiedProperties field that is an array of string with the names of the modified fields on the entity. That’s it!

      I hope this addresses your scenario.

      Cheers,
      Tony

      • Bobby says:

        Thanks for the quick response. Quick question, in reference to your methods list above:

        For ApplyChanges(), I get most of this with Julie’s method, it seems. I am even able to work with N:N relationships fine, with the exception of removals. Say I have a many to many relationship between Employee and Job. If I try to remove an Empoyee’s Job, but not the Job entry itself, the Job entry along with all other references to Job (other Employee’s Jobs) are removed. I would obviously need to fix this up.* I am guessing your solution does not do this. Also, can you explain what you mean by “correct order”?

        For LoadRelatedEntities(), I seem to get this on Context.SaveChanges(). What am I missing?

        In my scenario, asking the client to track the state of the entity, much less the changed properties is asking too much. I have even considered recursing the graph on the server once back from the client and setting state. I did like this about sending the original values to the client or loading them once back.

        Thanks again.

        * Obviously constructing the joining table with an identifier PK, instead of a composite between the relating tables lets me work with the joining table independently, but that is cumbersome.

      • Tony Sneed says:

        What ApplyChanges does is apply set Entity State for inserts, updates and deletes recursively throughout the object graph, including 1-1, 1-M, M-1 and M-M relations. That’s not possible with the DbContext API described by Julie. In particular, deletes on M-M relations are problematic, as you noted, because M-M are ‘independent associations’ only, versus foreign key associations. As a result, marking setting the Entity State to deleted for an entity on the many side will delete the entity, which is not what you want! What I’ve done with ApplyChanges is to dip down to the ObjectContext layer to remove the association without deleting the entity.

        LoadRelatedEntities is roughly analogous to ObjectContext.LoadProperty. It’s needed for inserts, because when you create a new entity you usually only set the foreign key property. For example, you create a new Order, which has a CustomerId property, as well as a Customer property. On the client, you would set CustomerId and not Customer. But when the new Order is saved in the Web API method, you would want to return an Order with the Customer property populated. You could use the LoadProperty method to do this, but that method is not exposed by DbContext, and it’s not asynchronous. Plus you have to call it for every entity. What LoadRelatedEntities does is compose a dynamic Entity SQL statement for fetching batches of related entities, and it does so asynchronously. For example, if you added an Order with several OrderDetail children, and each of those had a Product property, LoadRelatedEntities fetches all the unique products for that order in one query.

        Client-side change-tracking is always the tough part. I’ve spent quite a bit of time working on the change tracker, and it’s challenging to cover all scenarios. Once you tackle that problem, however, it’s simply a matter of applying those changes on the server. What I’ve tried to do with TE is make the communication between client and server as efficient as possible. This is accomplished with a GetChanges method on the client change-tracker, which extracts only entities that have been added, modified or removed, so that unchanged entities are not transmitted. However, an entity will be sent if there is a downstream change in the object graph.

        Cheers,
        Tony

      • Bobby says:

        Probably missing something, but it appears Julie’s method sets the state on each entity:

        context.ChangeTracker.Entries().Each(e =>
        {
        var stateInfo = e.Entity;
        e.State = ConvertState(stateInfo.EntityState);

        if (stateInfo.EntityState == eEntityState.Unchanged)
        ApplyPropertyChanges(e.OriginalValues, stateInfo.OriginalValues);

        For each entry, it first sets the state; if then, the state is Unchanged (Not Added or Deleted) – the client does not set Modified at entity or property level – it updates the properties recursively, setting the entity to Modified. Again, I am probably missing your point.

        For handling M-M, I am going to revert back to how I have typically handled this, which is to explicitly map a junction table and make the client manage that though, it is a little extra effort.

        I get LoadRelatedEntities() now. That’s quite nice.

      • Tony Sneed says:

        Yes, both my ApplyChanges and Julie’s example set EntityState on each change tracker entry. The difference is a) ApplyChanges does this recursively. For example, you have an Order with OrderDetails. What ApplyChanges does is go all the way down the object graph. So let’s say your Order has a detail that is added, another that is modified, and a third which is supposed to be deleted. The Order itself can be either unchanged or modified. You would have to set entity state on each entity in the object graph. Now, there’s nothing to stop you from doing that manually. But wouldn’t it be nice if there were a method that could traverse the object graph for you? That’s precisely what my ApplyChanges method does. 🙂

        But in addition, b) it handles many-to-many relationships by dipping down to the ObjectContext API. That’s far superior than creating an entity that represents the intersection table. Again, this is something you can do yourself, and Julie also describes this in one of her books. But it’s quite convenient to have a method that handles the many-to-many scenario, and does so recursively. What the recursion will do in this case is to apply downstream changes on either side of the n:n relation, for example if those entities in turn have child entities.

        The interesting side-effect of using Trackable Entities as a server-side library to assist with persistence of entities in a disconnected manner is that you can leverage a Visual Studio template that generates the Web API code for you. This is similar to the EF-specific scaffolding available in VS for Web API. The difference with Trackable Entities is that this comes as a VS item template, which has a wizard for selecting the context and entity classes. Check out the TE Getting Started Video, in which I put together a complete end-to-end N-Tier app with EF and Web API in less than 10 minutes.

      • Bobby says:

        When you say ApplyChanges() does this recursively, without having to set the state on every entity, this may be true when using both your client and server-side functionality, but in my tests, I had to explicitly set state on every entity. Also, I could never get a M:M Add() to work (human has hobbies), regardless of what I set state on – always the foreign key constraint violation. Perhaps I am doing something incorrectly, as I don’t fully understand how your code works and what I need to do on the client, not using your client framework.

        Human human;
        Hobby hobby;

        human = new Human
        {
        Name = “Bobby”,
        TrackingState = TrackingState.Added
        };

        hobby = new Hobby
        {
        Name = “golf”,
        //TrackingState = TrackingState.Added
        };

        human.Hobbies.Add(hobby);

      • Tony Sneed says:

        When you say ApplyChanges() does this recursively, without having to set the state on every entity, this may be true when using both your client and server-side functionality, but in my tests, I had to explicitly set state on every entity.

        Yes, that’s the point. ApplyChanges looks at the TrackingState property on each entity in order to apply Entity State, and it does this recursively. What I’m saying is that, if you figure out a way to set this field on the client, then ApplyChanges provides a great deal of value, both because of the recursive capability, and the support for many-to-many. The pay off is that you only need to call ApplyChanges for the magic to happen – that’s just one line of code in your Web API action. If, on the other hand, you are setting Entity State yourself, then yes, you have to call it on each entity non-recursively, which could require many lines of code, depending on the shape and depth of your object graph, and this would be code you would have to write for each and every action. And you would need to use the ObjectContext API to handle n:n. Why do all that when you have a handy open-source library available that does it for you?

        So the question is, then, how do you set the TrackingState field on the client? What I’m saying is that there is no need to use Trackable Entities on the client-side to achieve this. The only thing ApplyChanges on the server-side expects is that each entity has a TrackingState property with a value set to 0-Unchanged, 1-Added, 2-Modified, or 3-Deleted. It doesn’t care how this is set and is completely platform agnostic. What I suggest is that, in order to take advantage of ApplyChanges, you set this field on the client side, then send the object graph to the server where that change state can be persisted by calling ApplyChanges. But what you’d need is some sort of change-tracking mechanism on the client which sets that field.

        In the example you gave, you would need to set TrackingState to Added for the hobby, because you are setting it manually. If you were using the client-side library for TE, then the change tracker would mark it on the Add method. Because collections are materialized as ChangeTrackingCollection, the TrackingState is set automatically when entities are added, modified or removed, and the deletes are cached, so that they can be included when you call GetChanges on the change tracker. But that’s using TE on the client. You would have to set the state yourself on the client before sending entities to the server for persistence.

      • Bobby says:

        Now, If I have a regular 1:N, and I try to add a new parent and multiple children, only one child is added, whether I set all the children to Added or not. That is strange.

        Just got your response. Okay, now we’re connecting, I think. So, I am basically in the same boat as with Julie’s of having to find a way to set state for every entity, whether I write something to do that automatically or manually. Unfortunately, creating this functionality – something like INotifiyPropertyChanged – for the client is not doable, in my case.

        Thanks for the going back and forth… and the code snippet.

      • Tony Sneed says:

        The problem with multiple adds may be a bug, which has been fixed. To get the latest, select “Include Pre-release” in the NuGet options. You should get beta1 which has the fix.

      • Bobby says:

        If I have already added the parent to the DB, then reload it, I can then add the child M;M, if I set its state to added, but I can’t add both in one operation.

        Also, if I then try to delete the child by setting its state to Deleted, it deletes both the link table entry, as well as the entity on the other side. This is what I got away from by having the explicit linking entity. Again, perhaps using your client side bits, it works as expected/described.

      • Tony Sneed says:

        Here is the code you need to perform deletes (as well as adds) for many-to-many:

        private static void SetRelationshipState(this DbContext context,
        object item, object parent, string propertyName, EntityState entityState)
        {
        // Set relationship state for independent association
        var stateManager = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager;
        stateManager.ChangeRelationshipState(parent, item, propertyName, entityState);
        }

        Here is an example on Stack Overflow.

      • Bobby says:

        I saw this, stepping through your code. Thanks.

      • Bobby says:

        With a regular 1:N scenario, I could do an add of a new parent and child, by just setting the parent state to Added. So, that was different, from previous update cases where I had to set the state on each entity (never got this far with M:M add).

        Now, when I try to reload this 1:M graph and update only the child, I must set the child state to modified. Only setting the parent to modified does nothing for the child. Stated otherwise, to update anything in a regular 1:N, I have to explicitly set the state of the entity I want to delete. So, no recursion that I see and same as Julie’s.

        Now, if I load this 1:N graph and set only the parent to deleted, it deletes both the parent and child, which I guess makes sense. I would maybe prefer to need to set a cascade rule, or set state on each individually in the case of deletes. Now, if I just set the child to deleted, it deletes only the child, which makes sense.

        Looking more and more like to get the recursive functionality, you may have to use the client side stuff too.

      • Tony Sneed says:

        One thing I would suggest is taking a look at the source code for ApplyChanges. It recurses when it needs to, but it relies on DbContext to recurse when it can (for example, with inserts).

  7. Bobby says:

    BTW, I tried the approach of only using your server side functionality and setting state manually at the client, in a many to many scenario (Human can have many Hobbies, w\HumanHobby joining table), but I get a foreign key constraint violation (Hobby table). What do I need to do differently on the client to make this work? Thanks.

    Client:

    Human human;

    human = new Human
    {
    Name = “Bobby”,
    TrackingState = TrackingState.Added
    };

    human.Hobbies.Add(new Hobby
    {
    Hobby1 = “golf”,
    TrackingState = TrackingState.Added
    });

    Server:

    using (var context = new ManyToManyContext())
    {
    context.ApplyChanges(human);

    try
    {
    await context.SaveChangesAsync();
    }
    catch (DbUpdateException ex)
    {
    string a = ex.Message;
    }

    await context.LoadRelatedEntitiesAsync(human);
    human.AcceptChanges();
    }

    • Tony Sneed says:

      This error usually results from failing to sync the FK value with the related property. For example, if you set Customer on Order, you need to make sure that the CustomerId on Customer matched the CustomerId on Order. That’s most likely the cause of the error.

      For an example of M-M, download the samples and take a look at the SampleApi.Relations project.

      • Bobby says:

        I get that, but I shouldn’t have to set Primary/Foreign keys on an Add(), as in the example above (both parent and child are new), which is not a N:N scenario. I’ll look over it again. Thanks.

  8. Bobby says:

    Oops, sorry, not enough sleep. The example was N:N. Thanks again.

  9. Tom McKeown says:

    I’m a bit lost, how does the client get one version of the Product class (with the different collection for orders) while the server is using a different one? Aren’t these suppose to be the same class or is the client one a DTO?

    • Tony Sneed says:

      Neither WCF nor Web API require that entity classes be shared between client and server. For WCF, the same DataContract Namespace must be used, but the types can belong to different CLR namespaces. Collection-types can be different as well, for example, List on the server version of the entity, and ObservableCollection on the client version. All that matters is that the serializer knows how to convert the wire format (JSON, XML, etc) to and from the .NET types. This provides for greater flexibility and separation of concerns. For example, there’s no reason why the server would need to have entities that implement INotifyPropertyChanged, because that is purely to support data binding and change-tracking, which are client concerns.

      • tommymckeown says:

        Thanks Tony, I understand the point but isn’t this essentially the same as DTO objects? There is still the burden of coding 2 versions of a Domain class yes?

      • Tony Sneed says:

        These are DTO’s, and you have the option of sharing the types between client and server. But the cleaner separation is made possible because the entires are generated base on either a database schema (Code First) or a Data Model (Designer First). Both are supported by the latest version of Trackable Entities.

  10. tommymckeown says:

    ok, so your product allows me to choose that and auto generates the client (dto) with “Observable” collections etc…. I get it…. very cool. I need to look at it closer.

  11. tommymckeown says:

    Tony, I have a question about the WCF DataContract residing on client and server but are differrent types… When I create my service reference from my client to the service it generates the proxy class instead of using the data contract class on my client. How can I pass my client native class to the WCF service class that was defined using the server side type, both have the same data contract name and namespace. I know this isn’t related to your product but I can’t find any examples on how to make this work…

  12. tommymckeown says:

    The solution I have found to work was to use the channel factory, and create my own client side ServiceContract and DataContract, at first I didn’t like it but I realized that is exactly what the ServiceReference is doing anyway. I put a common name and namespace on the ServiceContractAttribute and the DataContractAttribute on both the client and server. Now I can have independent development/evolution of my classes. I think this is the same approach you are suggesting.

    • Tony Sneed says:

      Yes, this is it. I favor separate classes on client and server in order to get better separation of concerns. For example, on the client we need to think about change tracking and data binding, but these might not be a concern on the server, which only needs to apply changes. Some scenarios favor shared classes between client and server, so we’re going to try to support that in the future, but my preference is for greater separation, and you get that with ChanngelFactory on the client using a separate assembly for client entities.

  13. akn says:

    Hi Tony, this seems quite old now.. many of the links are broken as well. Is this package still under active development? I wanted to give this a try but I’m skeptical due to broken links and outdated packages in the sample solution.
    I can update the Nuget packages etc but wanted to hear from you about the state of this package
    Please reply.

  14. akn says:

    I would love to get involved.. although I’m under some deadlines right now. I should be able to a few hours on the weekends.

  15. Pingback: Real Life Entity Framework n-tier development – Embracing the cloud

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.