Friday, August 01, 2008

ADO.NET Data Services: Creating a custom Data Context #3: Updating

This follows part 1 where I create a custom data context and part 2 where I create a client application to talk to it.

For your custom data context to allow for updates you have to implement IUpdatable.

ado_net_im_iupdatable

This interface has a number of cryptic methods and it wasn't at all clear at first how to write an implementation for it. I'm sure there must be some documentation somewhere but I couldn't find it. I resorted to writing trace writes in the empty methods and firing inserts and updates at my web service. You can then use Sysinternals' DebugView to watch what happens.

First of all lets try an insert:

public void AddANewTeacher()
{
  Console.WriteLine("\r\nAddANewTeacher");

  var frankyChicken = new Teacher
                        {
                            ID = 3,
                            Name = "Franky Chicken"
                        };
  service.AddObject("Teachers", frankyChicken);
  var response = service.SaveChanges();
}

We get this result:

ado_net_im_debug_insert

So you can see that first all the existing Teachers are returned, then a new Teacher instance is created, it's properties set, SaveChanges is called and then ResolveResource. For my simple in-memory implementation I just added the new Teacher to my static list of teachers:

public object CreateResource(string containerName, string fullTypeName)
{
  Trace.WriteLine(string.Format("CreateResource('{0}', '{1}')", containerName, fullTypeName));

  var type = Type.GetType(fullTypeName);
  var resource = Activator.CreateInstance(type);

  switch (containerName)
  {
      case "Teachers":
          Root.Teachers.Add((Teacher)resource);
          break;
      case "Courses":
          Root.Courses.Add((Course)resource);
          break;
      default:
          throw new ApplicationException("Unknown containerName");
  }

  return resource;
}

public void SetValue(object targetResource, string propertyName, object propertyValue)
{
  Trace.WriteLine(string.Format("SetValue('{0}', '{1}', '{2})", targetResource, propertyName, propertyValue));

  Type type = targetResource.GetType();
  var property = type.GetProperty(propertyName);
  property.SetValue(targetResource, propertyValue, null);
}

Next let's try an update:

public void UpdateATeacher()
{
  Console.WriteLine("\r\nUpdateATeacher");

  var fredJones = service.Teachers.Where(t => t.ID == 2).Single();

  fredJones.Name = "Fred B Jones";

  service.UpdateObject(fredJones);
  service.SaveChanges();
}

We get this result:

ado_net_im_debug_update

This time the Teacher to be updated is returned by GetResource then SetValue is called to update the Name property. Finally SaveChanges and ResolveResources are called again.

The GetResource implementation is straight from Shawn Wildermuth's LINQ to SQL implementation.

public object GetResource(IQueryable query, string fullTypeName)
{
  Trace.WriteLine(string.Format("GetResource('query', '{0}')", fullTypeName));

  // Get the first result
  var results = (IEnumerable)query;
  object returnValue = null;
  foreach (object result in results)
  {
      if (returnValue != null) break;
      returnValue = result;
  }

  // Check the Typename if needed
  if (fullTypeName != null)
  {
      if (fullTypeName != returnValue.GetType().FullName)
      {
          throw new DataServiceException("Incorrect Type Returned");
      }
  }

  // Return the resource
  return returnValue;
}

Now all I have to do is work on creating relationships between entities, possibly more on this next week.

Code is here:

http://static.mikehadlow.com/Mike.DataServices.InMemory.zip

2 comments:

Anonymous said...

I'm glad to read your articles serial about ado.net data services. It did help me a lot. Can't wait to see more..
Good work, keep going!

Anonymous said...

oho good dear !!!! very interesting blog and a good posting !!! you must maintain your blog, its interesting !!! Nice Buddy
________________________________

Research Papers To Buy