In most of the projects, we use Entity Framework as ORM. It works ok in most cases.
We always try to hide the state object as much as possible, we try to encapsulate the state objects with Domain Entities. Repositories can be used to retrieve these Domain Entities.

For a project, we needed to store serialized data in a state object. These are some reasons why we chose to store data serialized:

  • The data structure can vary by entity
  • There is no need to query this data
  • It is a complex structure and would require lots of tables to store it deserialized

We need to make sure this serialized data is always up to date (serialized) before saving.
In a first attempt, we serialized the state at every command on the Entity.
When the API of my Entity grew, the serializations increased. It wasn’t a performance issue yet, but it also wasn’t one of the pieces of code to be proud of.
So we started brainstorming and came to the following solution.

We created the following interface:

public interface ICanBeOutOfSync
{
    void SyncMe();
}

All state objects with serialized state implement this interface.

Now we need to implement this method on our state objects. We do not want a reference from a state object to the entity so we provided a method on the state object in which the entity can provide an Action to Sync the state:

public class MyEntityState : ICanBeOutOfSync
{
    public void SyncMe()
    {
        _syncMethod();
    }

    private Action _syncMethod;
    public void RegisterSyncMethod(Action syncMethod)
    {
        _syncMethod = syncMethod;
    }
}

Now that we can call SyncMe() on the state object, we want to force that this method is called before SaveChanges() is called on the DbContext.

public class MyDataContext : DbContext
{
    public override int SaveChanges()
    {
        SyncEntitiesWhoCanBeOutOfSync();
    
        base.SaveChanges();
    }

    private void SyncEntitiesWhoCanBeOutOfSync()
    {
        var syncableEntities = ChangeTracker.Entries().Where(e => e.Entity.GetType().GetInterfaces().Any(x => x == typeof(ICanBeOutOfSync)));

        foreach (var syncableEntity in syncableEntities)
        {
            ((ICanBeOutOfSync)syncableEntity.Entity).SyncToMe();
        }
    }
}

The SaveChanges() of the DbContext is overridden and we make sure all Entities are synced.
We ask the ChangeTracker for all ICanBeOutOfSync Entities and call SyncMe() on all Entities to make sure they update their serialized data. When the serialized data is changed, the ChangeTracker will set the state to Modified.
When syncing is completed, we can call the SaveChanges() of the DbContext and let EntityFramework do its work.

The following two tabs change content below.
I'm a software developer from Utrecht. Interested in DDD, continuous delivery, new technologies & frameworks.

Latest posts by Vincent Keizer (see all)