ADO.NET Data Services – Batching in Action

I did a talk on Data Services at DevDays, Amsterdam last week and so I had to take a rather speedy look at batching support as that had been added to the VS 2008 Sp1 bits since the previous preview.

Batching is explained up here but here’s just a little example of using it.

If we take “hello world” style service that we created back in this post and we were to do something like this from the .NET client side code;

  static void Main(string[] args)
  {
    Console.ReadLine();

    NorthwindEntities proxy = new NorthwindEntities(
      new Uri("https://localhost/SecureSite/Secure/Service.svc"));

    foreach (Shippers s in proxy.Shippers)
    {
      Console.WriteLine(s.ShipperID);
    }

    foreach (Employees e in proxy.Employees)
    {
      Console.WriteLine(e.EmployeeID);
    }

    Console.ReadLine();
  }

and if we were to go ahead and trace that traffic with Fiddler then we’d see;

image

That is – we see and HTTP GET request for Shippers and then another one for Employees. Now, if these 2 entity sets are related then we can use the $expand query string operator in order to bring back the related data as the response to a single GET but it would be easier even here just to try and use batching to reduce the number of round trips and we can do that with something like;

static void Main(string[] args)
  {
    Console.ReadLine();

    NorthwindEntities proxy = new NorthwindEntities(
      new Uri("http://mthpvista/SecureSite/Secure/Service.svc"));

    DataServiceResponse responses =
      proxy.ExecuteBatch(
        new DataServiceRequest<Shippers>(new Uri("Shippers", UriKind.Relative)),
        new DataServiceRequest<Employees>(new Uri("Employees", UriKind.Relative)));

    foreach (QueryResponse item in responses)
    {
      foreach (Shippers s in item.OfType<Shippers>())
      {
        Console.WriteLine(s.ShipperID);
      }
      foreach (Employees e in item.OfType<Employees>())
      {
        Console.WriteLine(e.EmployeeID);
      }
    }

    Console.ReadLine();
  }

So, now we’re using ExecuteBatch in order to send any number of queries to the server in a single shot and we get back a number of responses. If we look at Fiddler, we see;

image

and so we’ve sent a single POST to the $batch endpoint and in that single post is a request for 2 GET operations – one for Shippers and one for Employees and then we get back 2 responses in the response stream.

The other side of batching ( and possibly the more common one ) is when you want to do multiple inserts, updates, deletes. Again, I could see using this when I want to minimise round-trips but, more so, when I want to get a bunch of changes submitted to the server as a single operation rather than a set of separate posts. I guess the classic example would be to insert a customer with 3 orders – you’d really like this to happen in a single post but I guess that RESTful systems have to have a mechanism for dealing with the intermediate case if you do submit the inserts as 4 separate POSTs.

If I use code such as;

static void Main(string[] args)
  {
    Console.ReadLine();

    NorthwindEntities proxy = new NorthwindEntities(
      new Uri("http://mthpvista/SecureSite/Secure/Service.svc"));

    for (int i = 0; i < 3; i++)
    {
      Customers newC = new Customers()
      {
        CustomerID = string.Format("ACME{0}", i),
        CompanyName = string.Format("Comp{0}", i)
      };
      proxy.AddToCustomers(newC);
    }
    proxy.SaveChanges();

    Console.ReadLine();
  }

 

then what I see as a result of my inserts is;

image

That is, I get 3 POSTs for my 3 customers that are being inserted. There’s an easy way to cut that down to a single POST which would be to change the way in which I’m calling SaveChanges in order to pass a SaveChangesOption value of Batch;

  static void Main(string[] args)
  {
    Console.ReadLine();

    NorthwindEntities proxy = new NorthwindEntities(
      new Uri("http://mthpvista/SecureSite/Secure/Service.svc"));

    for (int i = 0; i < 3; i++)
    {
      Customers newC = new Customers()
      {
        CustomerID = string.Format("ACME{0}", i),
        CompanyName = string.Format("Comp{0}", i)
      };
      proxy.AddToCustomers(newC);
    }
    proxy.SaveChanges(SaveChangesOptions.Batch);

    Console.ReadLine();
  }

and now what I see is a single POST sent to the $batch endpoint with the request for 3 inserts in it;

image