ef_vs_nhibernate

Entity Framework 6 Change Tracking POCOs vs nHibernate

Let me warn you that this post is kind of a rant. Entity Framework is on version 6 and Code First with POCOs still can’t track changes on detached object graphs that has been sent over the wire. The scenario is quite simple:

  1. A client request an entity from the server, e.g. asp.net mvc controller renders a view.
  2. The client modifies the entity and posts it back, i.e. form post.
  3. The MVC model binder deserializes the form data to our domain model.
  4. The MVC controller should be able to update the database without first fetching the data and applying the update per property.

Well this isn’t entirely fair since we can actually do this for first level properties, but not for navigation properties, e.g. has-many relationships. NHibernate has been able to do this for ages.

A colleague working on the web team asked me for help regarding this matter and I knew that this was the case in EF4/5, but I figured they’ve implemented it by now. So I threw together a test, just to confirm that it was still as bad as I remembered it.

Let’s say our db context looks like this:

public class Db : DbContext
{
    public Db() : base("Db")
    {
        Configuration.LazyLoadingEnabled = true;
    }

    public DbSet Foos { get; set; }
    public DbSet Bars { get; set; }
}

With the following entities:

public class Foo
{
    public int Id { get; set; }
    public string Value { get; set; }
    public virtual ICollection Bars { get; set; }
}

public class Bar
{
    public int Id { get; set; }
    public string Value { get; set; }

    public int FooId { get; set; }
    public virtual Foo Foo { get; set; }
}

Our db initializer just adds one record of Foo that has a child record Bar with the values Value:

public class DbInitializer : DropCreateDatabaseAlways
{
    protected override void Seed(Db context)
    {
        context.Foos.Add(new Foo
        {
            Value = "Value", 
            Bars = new List
            {
                new Bar { Value = "Value" }
            }
        });

        context.SaveChanges();
    }
}

Our test first reads the entity and disposes the context, i.e. the graph is now detached. We make some changes to the detached graph and try to apply the changes by passing the object to SaveOrUpdate with a new db context, i.e. simulating a post from the client to our server:


[TestFixture]
public class Test
{
    [Test]
    public void TestChangeTracking()
    {
        System.Data.Entity.Database.SetInitializer(new DbInitializer());
        
        Foo foo;
        // Read and send to the client over the wire
        using (var db = new Db())
        {
            foo = db.Foos.First();
            Assert.AreEqual(1, foo.Bars.Count);
        }

        // Client changes some values
        foo.Value = "Changed";
        foo.Bars.First().Value = "Changed";

        // Post to server for an update
        using (var db = new Db())
        {
            db.Foos.AddOrUpdate(foo);
            db.SaveChanges();
        }

        // What got saved?
        using (var db = new Db())
        {
            foo = db.Foos.First();
            Console.WriteLine("Foo.Value: {0}", foo.Value);
            Console.WriteLine("Foo.Bars[0].Value: {0}", foo.Bars.First().Value);
        }

        Assert.Fail("Use nhibernate instead.");
    }
}

What got saved? Foo.Value got updated to Changed but Bars didn’t. Pretty lame if you ask me. If you insist on using EF instead of nhibernate you’ll need to fetch the record in the new db context, diff and apply the changes to it and save.

ef_update_fail

Hope they do something about this soon, until next time, have a great weekend!

Asynchronous proxy for a synchronous WCF service

I recently had this scenario while working for a client where we wanted to consume a synchronous service asynchronously. We couldn’t change the service contract since it would break other proxy implementations. Luckily conventions implemented by the guys at microsoft made this task surprisingly easy, this is how we solved it.

Let’s say our service contract looks like this:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetData(int value);
}

With the following service implementation:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
}

An synchronous proxy would look something like this:

class ServiceClient : IService1
{
    private readonly IService1 _channel;

    public ServiceClient()
    {
        var factory = new ChannelFactory(binding, address);
        _channel = factory.CreateChannel();
    }

    public string GetData(int value)
    {
        return _channel.GetData(value);
    }
}

And consuming it synchronously is trivial:

var client = new ServiceClient();
var data = client.GetData(10)

So how do we consume this asynchronously? We simply define a parallel async service contract with the same ServiceContract name, like this:

[ServiceContract(Name = "IService1")]
interface IService1Async
{
    [OperationContract]
    Task GetDataAsync(int value);
}

And an asynchronous proxy would look something like this:

class ServiceClientAsync : IService1Async
{
    private readonly IService1Async _channel;

    public ServiceClientAsync()
    {
        var factory = new ChannelFactory(binding, address);
        _channel = factory.CreateChannel();
    }

    public Task GetDataAsync(int value)
    {
        return _channel.GetDataAsync(value);
    }
}

And consuming it asynchronously becomes trivial:

var client = new ServiceClientAsync();
var data = await client.GetDataAsync(10);

To summarize: The convention is as long as the service name is the same on the contract the method will be called if the method name matches and also if you’ve appended Async to the method name. Pretty smooth imho, and all without the need to change the “legacy service” contract.

Cheers!