In the first demo, we get disconnected entity, make change of it, and get copy of original copy from the database, and apply the changed entity to the original entity by using context.ApplyPropertyChanges method, and save it back to the database.

public void DemoDisconnectedUpdate1()
{
    //using NoTracking to simulate the disconnected enviorment
    //or you can use context.Detach() to simulate that
    context.Contacts.MergeOption = MergeOption.NoTracking;
    var pendingContact = context.Contacts.Where(c => c.ContactID == 709).First();
    //change
    pendingContact.FirstName = "somebody";
    //
    ApplyChange1(pendingContact);
}

public void ApplyChange1(EntityObject pendingEntity)
{
    context = new PEF();
    context.GetObjectByKey(pendingEntity.EntityKey);
    context.ApplyPropertyChanges(pendingEntity.EntityKey.EntitySetName, pendingEntity);
    context.SaveChanges();
}

Unlike the first demo, in the second demo, we use a anonymous typed object to represent the change of the entity, and apply the change directly to the original version directly using reflection.

public void DemoDisconnectUpdate2()
{
    EntityKey key = new EntityKey("PEF.Contacts", "ContactID", 709);
    var changes = new { FirstName = "xyz" };
    UpdateEntity(key, changes);
}

public void UpdateEntity(EntityKey key, object changes)
{
    var original = context.GetObjectByKey(key);
    ApplyChange(changes, original);
    context.SaveChanges();
}

public void ApplyChange(object changes, object original)
{
    Type newType = changes.GetType();
    Type oldType = original.GetType();
    var newProperties =  newType.GetProperties();
    foreach (var newProperty in newProperties)
    {
        var oldProperty = oldType.GetProperty(newProperty.Name);
        if (oldProperty != null)
        {
            oldProperty.SetValue(original, newProperty.GetValue(changes, null), null);
        }
    }
}